rcsparse update: Also export the ViewVC license to cvs2svn_rcsparse.
[cvs2svn.git] / contrib / rcs_file_filter.py
blob32963aa193444fe8061c042973dcd67354447ee2
1 #! /usr/bin/python
3 # (Be in -*- python -*- mode.)
5 # ====================================================================
6 # Copyright (c) 2006-2008 CollabNet. All rights reserved.
8 # This software is licensed as described in the file COPYING, which
9 # you should have received as part of this distribution. The terms
10 # are also available at http://subversion.tigris.org/license-1.html.
11 # If newer versions of this license are posted there, you may use a
12 # newer version instead, at your option.
14 # This software consists of voluntary contributions made by many
15 # individuals. For exact contribution history, see the revision
16 # history and logs, available at http://cvs2svn.tigris.org/.
17 # ====================================================================
19 """Filter an RCS file."""
21 import sys
22 import os
23 import time
25 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
27 from cvs2svn_lib.rcsparser import Sink
28 from cvs2svn_lib.rcsparser import parse
31 def at_quote(s):
32 return '@' + s.replace('@', '@@') + '@'
35 def format_date(date):
36 date_tuple = time.gmtime(date)
37 year = date_tuple[0]
38 if 1900 <= year <= 1999:
39 year = '%02d' % (year - 1900)
40 else:
41 year = '%04d' % year
42 return year + time.strftime('.%m.%d.%H.%M.%S', date_tuple)
45 class WriteRCSFileSink(Sink):
46 """A Sink that outputs reconstructed RCS file contents."""
48 def __init__(self, f):
49 """Create a Sink object that will write its output into F.
51 F should be a file-like object."""
53 self.f = f
54 self.head = None
55 self.principal_branch = None
56 self.accessors = []
57 self.symbols = []
58 self.lockers = []
59 self.locking = None
60 self.comment = None
61 self.expansion = None
63 def set_head_revision(self, revision):
64 self.head = revision
66 def set_principal_branch(self, branch_name):
67 self.principal_branch = branch_name
69 def set_access(self, accessors):
70 self.accessors = accessors
72 def define_tag(self, name, revision):
73 self.symbols.append((name, revision,))
75 def set_locker(self, revision, locker):
76 self.lockers.append((revision, locker,))
78 def set_locking(self, mode):
79 self.locking = mode
81 def set_comment(self, comment):
82 self.comment = comment
84 def set_expansion(self, mode):
85 self.expansion = mode
87 def admin_completed(self):
88 self.f.write('head\t%s;\n' % self.head)
89 if self.principal_branch is not None:
90 self.f.write('branch\t%s;\n' % self.principal_branch)
91 self.f.write('access')
92 for accessor in self.accessors:
93 self.f.write('\n\t%s' % accessor)
94 self.f.write(';\n')
95 self.f.write('symbols')
96 for (name, revision) in self.symbols:
97 self.f.write('\n\t%s:%s' % (name, revision))
98 self.f.write(';\n')
99 self.f.write('locks')
100 for (revision, locker) in self.lockers:
101 self.f.write('\n\t%s:%s' % (locker, revision))
102 self.f.write(';')
103 if self.locking is not None:
104 self.f.write(' %s;' % self.locking)
105 self.f.write('\n')
106 if self.comment is not None:
107 self.f.write('comment\t%s;\n' % at_quote(self.comment))
108 if self.expansion is not None:
109 self.f.write('expand\t%s;\n' % at_quote(self.expansion))
110 self.f.write('\n')
112 def define_revision(
113 self, revision, timestamp, author, state, branches, next
115 self.f.write(
116 '\n%s\ndate\t%s;\tauthor %s;\tstate %s;\n'
117 % (revision, format_date(timestamp), author, state,)
119 self.f.write('branches')
120 for branch in branches:
121 self.f.write('\n\t%s' % branch)
122 self.f.write(';\n')
123 self.f.write('next\t%s;\n' % (next or ''))
125 def tree_completed(self):
126 pass
128 def set_description(self, description):
129 self.f.write('\n\ndesc\n%s\n' % at_quote(description))
131 def set_revision_info(self, revision, log, text):
132 self.f.write('\n')
133 self.f.write('\n')
134 self.f.write('%s\n' % revision)
135 self.f.write('log\n%s\n' % at_quote(log))
136 self.f.write('text\n%s\n' % at_quote(text))
138 def parse_completed(self):
139 pass
142 class FilterSink(Sink):
143 """A Sink that passes callbacks through to another sink.
145 This is intended for use as a base class for other filter classes
146 that modify the data before passing it through."""
148 def __init__(self, sink):
149 """Create a Sink object that will write its output into SINK.
151 SINK should be a cvs2svn_rcsparse.Sink."""
153 self.sink = sink
155 def set_head_revision(self, revision):
156 self.sink.set_head_revision(revision)
158 def set_principal_branch(self, branch_name):
159 self.sink.set_principal_branch(branch_name)
161 def set_access(self, accessors):
162 self.sink.set_access(accessors)
164 def define_tag(self, name, revision):
165 self.sink.define_tag(name, revision)
167 def set_locker(self, revision, locker):
168 self.sink.set_locker(revision, locker)
170 def set_locking(self, mode):
171 self.sink.set_locking(mode)
173 def set_comment(self, comment):
174 self.sink.set_comment(comment)
176 def set_expansion(self, mode):
177 self.sink.set_expansion(mode)
179 def admin_completed(self):
180 self.sink.admin_completed()
182 def define_revision(
183 self, revision, timestamp, author, state, branches, next
185 self.sink.define_revision(
186 revision, timestamp, author, state, branches, next
189 def tree_completed(self):
190 self.sink.tree_completed()
192 def set_description(self, description):
193 self.sink.set_description(description)
195 def set_revision_info(self, revision, log, text):
196 self.sink.set_revision_info(revision, log, text)
198 def parse_completed(self):
199 self.sink.parse_completed()
202 if __name__ == '__main__':
203 if sys.argv[1:]:
204 for path in sys.argv[1:]:
205 if os.path.isfile(path) and path.endswith(',v'):
206 parse(open(path, 'rb'), WriteRCSFileSink(sys.stdout))
207 else:
208 sys.stderr.write('%r is being ignored.\n' % path)
209 else:
210 parse(sys.stdin, WriteRCSFileSink(sys.stdout))