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."""
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
32 return '@' + s
.replace('@', '@@') + '@'
35 def format_date(date
):
36 date_tuple
= time
.gmtime(date
)
38 if 1900 <= year
<= 1999:
39 year
= '%02d' % (year
- 1900)
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."""
55 self
.principal_branch
= None
63 def set_head_revision(self
, 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
):
81 def set_comment(self
, comment
):
82 self
.comment
= comment
84 def set_expansion(self
, 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
)
95 self
.f
.write('symbols')
96 for (name
, revision
) in self
.symbols
:
97 self
.f
.write('\n\t%s:%s' % (name
, revision
))
100 for (revision
, locker
) in self
.lockers
:
101 self
.f
.write('\n\t%s:%s' % (locker
, revision
))
103 if self
.locking
is not None:
104 self
.f
.write(' %s;' % self
.locking
)
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
))
113 self
, revision
, timestamp
, author
, state
, branches
, next
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
)
123 self
.f
.write('next\t%s;\n' % (next
or ''))
125 def tree_completed(self
):
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
):
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
):
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."""
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()
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__':
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
))
208 sys
.stderr
.write('%r is being ignored.\n' % path
)
210 parse(sys
.stdin
, WriteRCSFileSink(sys
.stdout
))