Introduce proper XHTML boilerplate into the cvs2svn webpages.
[cvs2svn.git] / cvs2svn_lib / symbol_database.py
blob440a0173d42dd047f0817a82027e023ef6cd6f1b
1 # (Be in -*- python -*- mode.)
3 # ====================================================================
4 # Copyright (c) 2000-2006 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 database facilities used by cvs2svn."""
20 from __future__ import generators
22 from boolean import *
23 import config
24 from artifact_manager import artifact_manager
27 def match_regexp_list(regexp_list, s):
28 """Test whether string S matches any of the compiled regexps in
29 REGEXP_LIST."""
31 for regexp in regexp_list:
32 if regexp.match(s):
33 return True
34 return False
37 class SymbolDatabase:
38 """This database records information on all symbols in the RCS
39 files. It is created in pass 1 and it is used in pass 2."""
41 def __init__(self):
42 # A hash that maps tag names to commit counts
43 self.tags = { }
44 # A hash that maps branch names to lists of the format
45 # [ create_count, commit_count, blockers ], where blockers
46 # is a hash that lists the symbols that depend on the
47 # the branch. The blockers hash is used as a set, so the
48 # values are not used.
49 self.branches = { }
51 def register_tag_creation(self, name):
52 """Register the creation of the tag NAME."""
54 self.tags[name] = self.tags.get(name, 0) + 1
56 def _branch(self, name):
57 """Helper function to get a branch node that will create and
58 initialize the node if it does not exist."""
60 if not self.branches.has_key(name):
61 self.branches[name] = [ 0, 0, { } ]
62 return self.branches[name]
64 def register_branch_creation(self, name):
65 """Register the creation of the branch NAME."""
67 self._branch(name)[0] += 1
69 def register_branch_commit(self, name):
70 """Register a commit on the branch NAME."""
72 self._branch(name)[1] += 1
74 def register_branch_blocker(self, name, blocker):
75 """Register BLOCKER as a blocker on the branch NAME."""
77 self._branch(name)[2][blocker] = None
79 def branch_has_commit(self, name):
80 """Return non-zero if NAME has commits. Returns 0 if name
81 is not a branch or if it has no commits."""
83 return self.branches.has_key(name) and self.branches[name][1]
85 def find_excluded_symbols(self, regexp_list):
86 """Returns a hash of all symbols that match the regexps in
87 REGEXP_LIST. The hash is used as a set so the values are
88 not used."""
90 excludes = { }
91 for tag in self.tags:
92 if match_regexp_list(regexp_list, tag):
93 excludes[tag] = None
94 for branch in self.branches:
95 if match_regexp_list(regexp_list, branch):
96 excludes[branch] = None
97 return excludes
99 def find_branch_exclude_blockers(self, branch, excludes):
100 """Find all blockers of BRANCH, excluding the ones in the hash
101 EXCLUDES."""
103 blockers = { }
104 if excludes.has_key(branch):
105 for blocker in self.branches[branch][2]:
106 if not excludes.has_key(blocker):
107 blockers[blocker] = None
108 return blockers
110 def find_blocked_excludes(self, excludes):
111 """Find all branches not in EXCLUDES that have blocking symbols that
112 are not themselves excluded. Return a hash that maps branch names
113 to a hash of blockers. The hash of blockes is used as a set so the
114 values are not used."""
116 blocked_branches = { }
117 for branch in self.branches:
118 blockers = self.find_branch_exclude_blockers(branch, excludes)
119 if blockers:
120 blocked_branches[branch] = blockers
121 return blocked_branches
123 def find_mismatches(self, excludes=None):
124 """Find all symbols that are defined as both tags and branches,
125 excluding the ones in EXCLUDES. Returns a list of 4-tuples with
126 the symbol name, tag count, branch count and commit count."""
128 if excludes is None:
129 excludes = { }
130 mismatches = [ ]
131 for branch in self.branches:
132 if not excludes.has_key(branch) and self.tags.has_key(branch):
133 mismatches.append((branch, # name
134 self.tags[branch], # tag count
135 self.branches[branch][0], # branch count
136 self.branches[branch][1])) # commit count
137 return mismatches
139 def read(self):
140 """Read the symbol database from files."""
142 f = open(artifact_manager.get_temp_file(config.TAGS_LIST))
143 while 1:
144 line = f.readline()
145 if not line:
146 break
147 tag, count = line.split()
148 self.tags[tag] = int(count)
150 f = open(artifact_manager.get_temp_file(config.BRANCHES_LIST))
151 while 1:
152 line = f.readline()
153 if not line:
154 break
155 words = line.split()
156 self.branches[words[0]] = [ int(words[1]), int(words[2]), { } ]
157 for blocker in words[3:]:
158 self.branches[words[0]][2][blocker] = None
160 def write(self):
161 """Store the symbol database to files."""
163 f = open(artifact_manager.get_temp_file(config.TAGS_LIST), "w")
164 for tag, count in self.tags.items():
165 f.write("%s %d\n" % (tag, count))
167 f = open(artifact_manager.get_temp_file(config.BRANCHES_LIST), "w")
168 for branch, info in self.branches.items():
169 f.write("%s %d %d" % (branch, info[0], info[1]))
170 if info[2]:
171 f.write(" ")
172 f.write(" ".join(info[2].keys()))
173 f.write("\n")