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
23 The inheritance tree is as follows:
29 | +--CVSRevisionModification (* -> 'Exp')
31 | | +--CVSRevisionAdd ('dead' -> 'Exp')
33 | | +--CVSRevisionChange ('Exp' -> 'Exp')
35 | +--CVSRevisionAbsent (* -> 'dead')
37 | +--CVSRevisionDelete ('Exp' -> 'dead')
39 | +--CVSRevisionNoop ('dead' -> 'dead')
54 from cvs2svn_lib
.context
import Ctx
57 class CVSItem(object):
61 'revision_reader_token',
64 def __init__(self
, id, cvs_file
, revision_reader_token
):
66 self
.cvs_file
= cvs_file
67 self
.revision_reader_token
= revision_reader_token
69 def __eq__(self
, other
):
70 return self
.id == other
.id
72 def __cmp__(self
, other
):
73 return cmp(self
.id, other
.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
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
133 raise NotImplementedError()
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
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
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
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
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
185 branch_ids -- (list of int) ids of all CVSBranches rooted at this
188 branch_commit_ids -- (list of int) ids of first CVSRevision
189 committed on each branch rooted in this revision (for branches
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
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
202 properties -- (dict) the file properties that vary from revision
203 to revision. The get_properties() method combines the
204 properties found in SELF.cvs_file.properties with those here;
205 the latter take precedence. Keys are strings. Values are
206 strings (indicating the property value) or None (indicating
207 that the property should be left unset, even if it is set in
208 SELF.cvs_file.properties). Different backends can use
209 properties for different purposes; for cvs2svn these become
210 SVN versioned properties. Properties whose names start with
211 underscore are reserved for internal cvs2svn purposes.
213 properties_changed -- (None or bool) Will this CVSRevision's
214 get_properties() method return a different value than the same
215 call of the predecessor revision?
217 revision_reader_token -- (arbitrary) a token that can be set by
218 RevisionCollector for the later use of RevisionReader.
230 'first_on_branch_id',
240 'properties_changed',
246 timestamp
, metadata_id
,
248 rev
, deltatext_exists
,
249 lod
, first_on_branch_id
, ntdbr
,
250 ntdbr_prev_id
, ntdbr_next_id
,
251 tag_ids
, branch_ids
, branch_commit_ids
,
252 revision_reader_token
,
254 """Initialize a new CVSRevision object."""
256 CVSItem
.__init
__(self
, id, cvs_file
, revision_reader_token
)
258 self
.timestamp
= timestamp
259 self
.metadata_id
= metadata_id
260 self
.prev_id
= prev_id
261 self
.next_id
= next_id
263 self
.deltatext_exists
= deltatext_exists
265 self
.first_on_branch_id
= first_on_branch_id
267 self
.ntdbr_prev_id
= ntdbr_prev_id
268 self
.ntdbr_next_id
= ntdbr_next_id
269 self
.tag_ids
= tag_ids
270 self
.branch_ids
= branch_ids
271 self
.branch_commit_ids
= branch_commit_ids
272 self
.opened_symbols
= None
273 self
.closed_symbols
= None
274 self
.properties
= None
275 self
.properties_changed
= None
277 def _get_cvs_path(self
):
278 return self
.cvs_file
.cvs_path
280 cvs_path
= property(_get_cvs_path
)
282 def get_svn_path(self
):
283 return self
.lod
.get_path(self
.cvs_file
.cvs_path
)
285 def __getstate__(self
):
286 """Return the contents of this instance, for pickling.
288 The presence of this method improves the space efficiency of
289 pickling CVSRevision instances."""
292 self
.id, self
.cvs_file
.id,
293 self
.timestamp
, self
.metadata_id
,
294 self
.prev_id
, self
.next_id
,
296 self
.deltatext_exists
,
298 self
.first_on_branch_id
,
300 self
.ntdbr_prev_id
, self
.ntdbr_next_id
,
301 self
.tag_ids
, self
.branch_ids
, self
.branch_commit_ids
,
302 self
.opened_symbols
, self
.closed_symbols
,
303 self
.properties
, self
.properties_changed
,
304 self
.revision_reader_token
,
307 def __setstate__(self
, data
):
308 (self
.id, cvs_file_id
,
309 self
.timestamp
, self
.metadata_id
,
310 self
.prev_id
, self
.next_id
,
312 self
.deltatext_exists
,
314 self
.first_on_branch_id
,
316 self
.ntdbr_prev_id
, self
.ntdbr_next_id
,
317 self
.tag_ids
, self
.branch_ids
, self
.branch_commit_ids
,
318 self
.opened_symbols
, self
.closed_symbols
,
319 self
.properties
, self
.properties_changed
,
320 self
.revision_reader_token
) = data
321 self
.cvs_file
= Ctx()._cvs
_path
_db
.get_path(cvs_file_id
)
322 self
.lod
= Ctx()._symbol
_db
.get_symbol(lod_id
)
324 def get_properties(self
):
325 """Return all of the properties needed for this CVSRevision.
327 Combine SELF.cvs_file.properties and SELF.properties to get the
328 final properties needed for this CVSRevision. (The properties in
329 SELF have precedence.) Return the properties as a map {key :
330 value}, where keys and values are both strings. (Entries with
331 value == None are omitted.) Different backends can use properties
332 for different purposes; for cvs2svn these become SVN versioned
333 properties. Properties whose names start with underscore are
334 reserved for internal cvs2svn purposes."""
336 properties
= self
.cvs_file
.properties
.copy()
337 properties
.update(self
.properties
)
339 for (k
,v
) in properties
.items():
345 def get_property(self
, name
, default
=None):
346 """Return a particular property for this CVSRevision.
348 This is logically the same as SELF.get_properties().get(name,
349 default) but implemented more efficiently."""
351 if name
in self
.properties
:
352 return self
.properties
[name
]
354 return self
.cvs_file
.properties
.get(name
, default
)
356 def get_effective_prev_id(self
):
357 """Return the ID of the effective predecessor of this item.
359 This is the ID of the item that determines whether the object
360 existed before this CVSRevision."""
362 if self
.ntdbr_prev_id
is not None:
363 return self
.ntdbr_prev_id
367 def get_symbol_pred_ids(self
):
368 """Return the pred_ids for symbol predecessors."""
371 if self
.first_on_branch_id
is not None:
372 retval
.add(self
.first_on_branch_id
)
375 def get_pred_ids(self
):
376 retval
= self
.get_symbol_pred_ids()
377 if self
.prev_id
is not None:
378 retval
.add(self
.prev_id
)
379 if self
.ntdbr_prev_id
is not None:
380 retval
.add(self
.ntdbr_prev_id
)
383 def get_symbol_succ_ids(self
):
384 """Return the succ_ids for symbol successors."""
387 for id in self
.branch_ids
+ self
.tag_ids
:
391 def get_succ_ids(self
):
392 retval
= self
.get_symbol_succ_ids()
393 if self
.next_id
is not None:
394 retval
.add(self
.next_id
)
395 if self
.ntdbr_next_id
is not None:
396 retval
.add(self
.ntdbr_next_id
)
397 for id in self
.branch_commit_ids
:
401 def get_ids_closed(self
):
402 # Special handling is needed in the case of non-trunk default
403 # branches. The following cases have to be handled:
405 # Case 1: Revision 1.1 not deleted; revision 1.2 exists:
407 # 1.1 -----------------> 1.2
412 # * 1.1.1.1 closes 1.1 (because its post-commit overwrites 1.1
415 # * 1.1.1.2 closes 1.1.1.1
417 # * 1.2 doesn't close anything (the post-commit from 1.1.1.1
418 # already closed 1.1, and no symbols can sprout from the
419 # post-commit of 1.1.1.2)
421 # Case 2: Revision 1.1 not deleted; revision 1.2 does not exist:
423 # 1.1 ..................
428 # * 1.1.1.1 closes 1.1 (because its post-commit overwrites 1.1
431 # * 1.1.1.2 closes 1.1.1.1
433 # Case 3: Revision 1.1 deleted; revision 1.2 exists:
435 # ............... 1.2
440 # * 1.1.1.1 doesn't close anything
442 # * 1.1.1.2 closes 1.1.1.1
444 # * 1.2 doesn't close anything (no symbols can sprout from the
445 # post-commit of 1.1.1.2)
447 # Case 4: Revision 1.1 deleted; revision 1.2 doesn't exist:
454 # * 1.1.1.1 doesn't close anything
456 # * 1.1.1.2 closes 1.1.1.1
458 if self
.first_on_branch_id
is not None:
459 # The first CVSRevision on a branch is considered to close the
461 yield self
.first_on_branch_id
463 # If the 1.1 revision was not deleted, the 1.1.1.1 revision is
464 # considered to close it:
466 elif self
.ntdbr_prev_id
is not None:
467 # This is the special case of a 1.2 revision that follows a
468 # non-trunk default branch. Either 1.1 was deleted or the first
469 # default branch revision closed 1.1, so we don't have to close
470 # 1.1. Technically, we close the revision on trunk that was
471 # copied from the last non-trunk default branch revision in a
472 # post-commit, but for now no symbols can sprout from that
473 # revision so we ignore that one, too.
475 elif self
.prev_id
is not None:
476 # Since this CVSRevision is not the first on a branch, its
477 # prev_id is on the same LOD and this item closes that one:
480 def _get_branch_ids_recursively(self
, cvs_file_items
):
481 """Return the set of all CVSBranches that sprout from this CVSRevision.
483 After parent adjustment in FilterSymbolsPass, it is possible for
484 branches to sprout directly from a CVSRevision, or from those
485 branches, etc. Return all branches that sprout from this
486 CVSRevision, directly or indirectly."""
489 branch_ids_to_process
= list(self
.branch_ids
)
490 while branch_ids_to_process
:
491 branch
= cvs_file_items
[branch_ids_to_process
.pop()]
493 branch_ids_to_process
.extend(branch
.branch_ids
)
497 def check_links(self
, cvs_file_items
):
498 assert self
.cvs_file
== cvs_file_items
.cvs_file
500 prev
= cvs_file_items
.get(self
.prev_id
)
501 next
= cvs_file_items
.get(self
.next_id
)
502 first_on_branch
= cvs_file_items
.get(self
.first_on_branch_id
)
503 ntdbr_next
= cvs_file_items
.get(self
.ntdbr_next_id
)
504 ntdbr_prev
= cvs_file_items
.get(self
.ntdbr_prev_id
)
505 effective_prev
= cvs_file_items
.get(self
.get_effective_prev_id())
508 # This is the first CVSRevision on trunk or a detached branch:
509 assert self
.id in cvs_file_items
.root_ids
510 elif first_on_branch
is not None:
511 # This is the first CVSRevision on an existing branch:
512 assert isinstance(first_on_branch
, CVSBranch
)
513 assert first_on_branch
.symbol
== self
.lod
514 assert first_on_branch
.next_id
== self
.id
515 cvs_revision_source
= first_on_branch
.get_cvs_revision_source(
518 assert cvs_revision_source
.id == prev
.id
519 assert self
.id in prev
.branch_commit_ids
521 # This revision follows another revision on the same LOD:
522 assert prev
.next_id
== self
.id
523 assert prev
.lod
== self
.lod
526 assert next
.prev_id
== self
.id
527 assert next
.lod
== self
.lod
529 if ntdbr_next
is not None:
531 assert ntdbr_next
.ntdbr_prev_id
== self
.id
533 if ntdbr_prev
is not None:
534 assert ntdbr_prev
.ntdbr_next_id
== self
.id
536 for tag_id
in self
.tag_ids
:
537 tag
= cvs_file_items
[tag_id
]
538 assert isinstance(tag
, CVSTag
)
539 assert tag
.source_id
== self
.id
540 assert tag
.source_lod
== self
.lod
542 for branch_id
in self
.branch_ids
:
543 branch
= cvs_file_items
[branch_id
]
544 assert isinstance(branch
, CVSBranch
)
545 assert branch
.source_id
== self
.id
546 assert branch
.source_lod
== self
.lod
548 branch_commit_ids
= list(self
.branch_commit_ids
)
550 for branch
in self
._get
_branch
_ids
_recursively
(cvs_file_items
):
551 assert isinstance(branch
, CVSBranch
)
552 if branch
.next_id
is not None:
553 assert branch
.next_id
in branch_commit_ids
554 branch_commit_ids
.remove(branch
.next_id
)
556 assert not branch_commit_ids
558 assert self
.__class
__ == cvs_revision_type_map
[(
559 isinstance(self
, CVSRevisionModification
),
560 effective_prev
is not None
561 and isinstance(effective_prev
, CVSRevisionModification
),
565 """For convenience only. The format is subject to change at any time."""
567 return '%s:%s<%x>' % (self
.cvs_file
, self
.rev
, self
.id,)
570 class CVSRevisionModification(CVSRevision
):
571 """Base class for CVSRevisionAdd or CVSRevisionChange."""
575 def get_cvs_symbol_ids_opened(self
):
576 return self
.tag_ids
+ self
.branch_ids
579 class CVSRevisionAdd(CVSRevisionModification
):
580 """A CVSRevision that creates a file that previously didn't exist.
582 The file might have never existed on this LOD, or it might have
583 existed previously but been deleted by a CVSRevisionDelete."""
588 class CVSRevisionChange(CVSRevisionModification
):
589 """A CVSRevision that modifies a file that already existed on this LOD."""
594 class CVSRevisionAbsent(CVSRevision
):
595 """A CVSRevision for which the file is nonexistent on this LOD."""
599 def get_cvs_symbol_ids_opened(self
):
603 class CVSRevisionDelete(CVSRevisionAbsent
):
604 """A CVSRevision that deletes a file that existed on this LOD."""
609 class CVSRevisionNoop(CVSRevisionAbsent
):
610 """A CVSRevision that doesn't do anything.
612 The revision was 'dead' and the predecessor either didn't exist or
613 was also 'dead'. These revisions can't necessarily be thrown away
614 because (1) they impose ordering constraints on other items; (2)
615 they might have a nontrivial log message that we don't want to throw
623 # {(nondead(cvs_rev), nondead(prev_cvs_rev)) : cvs_revision_subtype}
625 # , where nondead() means that the cvs revision exists and is not
626 # 'dead', and CVS_REVISION_SUBTYPE is the subtype of CVSRevision that
627 # should be used for CVS_REV.
628 cvs_revision_type_map
= {
629 (False, False) : CVSRevisionNoop
,
630 (False, True) : CVSRevisionDelete
,
631 (True, False) : CVSRevisionAdd
,
632 (True, True) : CVSRevisionChange
,
636 class CVSSymbol(CVSItem
):
637 """Represent a symbol on a particular CVSFile.
639 This is the base class for CVSBranch and CVSTag.
643 id -- (int) unique ID for this item.
645 cvs_file -- (CVSFile) CVSFile affected by this item.
647 symbol -- (Symbol) the symbol affected by this CVSSymbol.
649 source_lod -- (LineOfDevelopment) the LOD that is the source for
652 source_id -- (int) the ID of the CVSRevision or CVSBranch that is
653 the source for this item. This initially points to a
654 CVSRevision, but can be changed to a CVSBranch via parent
655 adjustment in FilterSymbolsPass.
657 revision_reader_token -- (arbitrary) a token that can be set by
658 RevisionCollector for the later use of RevisionReader.
669 self
, id, cvs_file
, symbol
, source_lod
, source_id
,
670 revision_reader_token
,
672 """Initialize a CVSSymbol object."""
674 CVSItem
.__init
__(self
, id, cvs_file
, revision_reader_token
)
677 self
.source_lod
= source_lod
678 self
.source_id
= source_id
680 def get_cvs_revision_source(self
, cvs_file_items
):
681 """Return the CVSRevision that is the ultimate source of this symbol."""
683 cvs_source
= cvs_file_items
[self
.source_id
]
684 while not isinstance(cvs_source
, CVSRevision
):
685 cvs_source
= cvs_file_items
[cvs_source
.source_id
]
689 def get_svn_path(self
):
690 return self
.symbol
.get_path(self
.cvs_file
.cvs_path
)
692 def get_ids_closed(self
):
693 # A Symbol does not close any other CVSItems:
697 class CVSBranch(CVSSymbol
):
698 """Represent the creation of a branch in a particular CVSFile.
702 id -- (int) unique ID for this item.
704 cvs_file -- (CVSFile) CVSFile affected by this item.
706 symbol -- (Symbol) the symbol affected by this CVSSymbol.
708 branch_number -- (string) the number of this branch (e.g.,
709 '1.3.4'), or None if this is a converted CVSTag.
711 source_lod -- (LineOfDevelopment) the LOD that is the source for
714 source_id -- (int) id of the CVSRevision or CVSBranch from which
715 this branch sprouts. This initially points to a CVSRevision,
716 but can be changed to a CVSBranch via parent adjustment in
719 next_id -- (int or None) id of first CVSRevision on this branch,
722 tag_ids -- (list of int) ids of all CVSTags rooted at this
723 CVSBranch (can be set due to parent adjustment in
726 branch_ids -- (list of int) ids of all CVSBranches rooted at this
727 CVSBranch (can be set due to parent adjustment in
730 opened_symbols -- (None or list of (symbol_id, cvs_symbol_id)
731 tuples) information about all CVSSymbols opened by this
732 branch. This member is set in FilterSymbolsPass; before then,
735 revision_reader_token -- (arbitrary) a token that can be set by
736 RevisionCollector for the later use of RevisionReader.
749 self
, id, cvs_file
, symbol
, branch_number
,
750 source_lod
, source_id
, next_id
,
751 revision_reader_token
,
753 """Initialize a CVSBranch."""
756 self
, id, cvs_file
, symbol
, source_lod
, source_id
,
757 revision_reader_token
,
759 self
.branch_number
= branch_number
760 self
.next_id
= next_id
763 self
.opened_symbols
= None
765 def __getstate__(self
):
767 self
.id, self
.cvs_file
.id,
768 self
.symbol
.id, self
.branch_number
,
769 self
.source_lod
.id, self
.source_id
, self
.next_id
,
770 self
.tag_ids
, self
.branch_ids
,
772 self
.revision_reader_token
,
775 def __setstate__(self
, data
):
777 self
.id, cvs_file_id
,
778 symbol_id
, self
.branch_number
,
779 source_lod_id
, self
.source_id
, self
.next_id
,
780 self
.tag_ids
, self
.branch_ids
,
782 self
.revision_reader_token
,
784 self
.cvs_file
= Ctx()._cvs
_path
_db
.get_path(cvs_file_id
)
785 self
.symbol
= Ctx()._symbol
_db
.get_symbol(symbol_id
)
786 self
.source_lod
= Ctx()._symbol
_db
.get_symbol(source_lod_id
)
788 def get_pred_ids(self
):
789 return set([self
.source_id
])
791 def get_succ_ids(self
):
792 retval
= set(self
.tag_ids
+ self
.branch_ids
)
793 if self
.next_id
is not None:
794 retval
.add(self
.next_id
)
797 def get_cvs_symbol_ids_opened(self
):
798 return self
.tag_ids
+ self
.branch_ids
800 def check_links(self
, cvs_file_items
):
801 source
= cvs_file_items
.get(self
.source_id
)
802 next
= cvs_file_items
.get(self
.next_id
)
804 assert self
.id in source
.branch_ids
805 if isinstance(source
, CVSRevision
):
806 assert self
.source_lod
== source
.lod
807 elif isinstance(source
, CVSBranch
):
808 assert self
.source_lod
== source
.symbol
813 assert isinstance(next
, CVSRevision
)
814 assert next
.lod
== self
.symbol
815 assert next
.first_on_branch_id
== self
.id
817 for tag_id
in self
.tag_ids
:
818 tag
= cvs_file_items
[tag_id
]
819 assert isinstance(tag
, CVSTag
)
820 assert tag
.source_id
== self
.id
821 assert tag
.source_lod
== self
.symbol
823 for branch_id
in self
.branch_ids
:
824 branch
= cvs_file_items
[branch_id
]
825 assert isinstance(branch
, CVSBranch
)
826 assert branch
.source_id
== self
.id
827 assert branch
.source_lod
== self
.symbol
830 """For convenience only. The format is subject to change at any time."""
832 return '%s:%s:%s<%x>' \
833 % (self
.cvs_file
, self
.symbol
, self
.branch_number
, self
.id,)
836 class CVSBranchNoop(CVSBranch
):
837 """A CVSBranch whose source is a CVSRevisionAbsent."""
841 def get_cvs_symbol_ids_opened(self
):
847 # {nondead(source_cvs_rev) : cvs_branch_subtype}
849 # , where nondead() means that the cvs revision exists and is not
850 # 'dead', and CVS_BRANCH_SUBTYPE is the subtype of CVSBranch that
852 cvs_branch_type_map
= {
853 False : CVSBranchNoop
,
858 class CVSTag(CVSSymbol
):
859 """Represent the creation of a tag on a particular CVSFile.
863 id -- (int) unique ID for this item.
865 cvs_file -- (CVSFile) CVSFile affected by this item.
867 symbol -- (Symbol) the symbol affected by this CVSSymbol.
869 source_lod -- (LineOfDevelopment) the LOD that is the source for
872 source_id -- (int) the ID of the CVSRevision or CVSBranch that is
873 being tagged. This initially points to a CVSRevision, but can
874 be changed to a CVSBranch via parent adjustment in
877 revision_reader_token -- (arbitrary) a token that can be set by
878 RevisionCollector for the later use of RevisionReader.
885 self
, id, cvs_file
, symbol
, source_lod
, source_id
,
886 revision_reader_token
,
888 """Initialize a CVSTag."""
891 self
, id, cvs_file
, symbol
, source_lod
, source_id
,
892 revision_reader_token
,
895 def __getstate__(self
):
897 self
.id, self
.cvs_file
.id, self
.symbol
.id,
898 self
.source_lod
.id, self
.source_id
,
899 self
.revision_reader_token
,
902 def __setstate__(self
, data
):
904 self
.id, cvs_file_id
, symbol_id
, source_lod_id
, self
.source_id
,
905 self
.revision_reader_token
,
907 self
.cvs_file
= Ctx()._cvs
_path
_db
.get_path(cvs_file_id
)
908 self
.symbol
= Ctx()._symbol
_db
.get_symbol(symbol_id
)
909 self
.source_lod
= Ctx()._symbol
_db
.get_symbol(source_lod_id
)
911 def get_pred_ids(self
):
912 return set([self
.source_id
])
914 def get_succ_ids(self
):
917 def get_cvs_symbol_ids_opened(self
):
920 def check_links(self
, cvs_file_items
):
921 source
= cvs_file_items
.get(self
.source_id
)
923 assert self
.id in source
.tag_ids
924 if isinstance(source
, CVSRevision
):
925 assert self
.source_lod
== source
.lod
926 elif isinstance(source
, CVSBranch
):
927 assert self
.source_lod
== source
.symbol
932 """For convenience only. The format is subject to change at any time."""
935 % (self
.cvs_file
, self
.symbol
, self
.id,)
938 class CVSTagNoop(CVSTag
):
939 """A CVSTag whose source is a CVSRevisionAbsent."""
946 # {nondead(source_cvs_rev) : cvs_tag_subtype}
948 # , where nondead() means that the cvs revision exists and is not
949 # 'dead', and CVS_TAG_SUBTYPE is the subtype of CVSTag that should be