1 # (Be in -*- python -*- mode.)
3 # ====================================================================
4 # Copyright (c) 2000-2007 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 the SVNCommit classes.
19 There are five types of SVNCommits:
21 SVNInitialProjectCommit -- Initializes a project (creates its trunk,
22 branches, and tags directories).
24 SVNPrimaryCommit -- Commits one or more CVSRevisions on one or more
27 SVNBranchCommit -- Creates or fills a branch; that is, copies files
28 from a source line of development to a target branch.
30 SVNTagCommit -- Creates or fills a tag; that is, copies files from a
31 source line of development to a target tag.
33 SVNPostCommit -- Updates trunk to reflect changes on a non-trunk
41 from cvs2svn_lib
.common
import InternalError
42 from cvs2svn_lib
.context
import Ctx
43 from cvs2svn_lib
.symbol
import Branch
44 from cvs2svn_lib
.symbol
import Tag
48 """This represents one commit to the Subversion Repository."""
50 # textwrap.TextWrapper instance to be used for wrapping log messages:
51 text_wrapper
= textwrap
.TextWrapper(width
=76)
53 def __init__(self
, date
, revnum
):
54 """Instantiate an SVNCommit.
56 REVNUM is the SVN revision number of this commit."""
58 # The date of the commit, as an integer. While the SVNCommit is
59 # being built up, this contains the latest date seen so far. This
60 # member is set externally.
63 # The SVN revision number of this commit, as an integer.
66 def __getstate__(self
):
67 return (self
.date
, self
.revnum
,)
69 def __setstate__(self
, state
):
70 (self
.date
, self
.revnum
,) = state
72 def get_cvs_items(self
):
73 """Return a list containing the CVSItems in this commit."""
75 raise NotImplementedError()
78 """Return the author or this commit, or None if none is to be used.
80 The return value is exactly as the author appeared in the RCS
81 file, with undefined character encoding."""
83 raise NotImplementedError()
85 def get_log_msg(self
):
86 """Return a log message for this commit.
88 The return value is exactly as the log message appeared in the RCS
89 file, with undefined character encoding."""
91 raise NotImplementedError()
93 def get_warning_summary(self
):
94 """Return a summary of this commit that can be used in warnings."""
96 return '(subversion rev %s)' % (self
.revnum
,)
98 def get_description(self
):
99 """Return a partial description of this SVNCommit, for logging."""
101 raise NotImplementedError()
103 def output(self
, output_option
):
104 """Cause this commit to be output to OUTPUT_OPTION.
106 This method is used for double-dispatch. Derived classes should
107 call the OutputOption.process_*_commit() method appropriate for
108 the type of SVNCommit."""
110 raise NotImplementedError()
113 """ Print a human-readable description of this SVNCommit.
115 This description is not intended to be machine-parseable."""
117 ret
= "SVNCommit #: " + str(self
.revnum
) + "\n"
118 ret
+= " debug description: " + self
.get_description() + "\n"
122 class SVNInitialProjectCommit(SVNCommit
):
123 def __init__(self
, date
, projects
, revnum
):
124 SVNCommit
.__init
__(self
, date
, revnum
)
125 self
.projects
= list(projects
)
127 def __getstate__(self
):
129 SVNCommit
.__getstate
__(self
),
130 [project
.id for project
in self
.projects
],
133 def __setstate__(self
, state
):
134 (svn_commit_state
, project_ids
,) = state
135 SVNCommit
.__setstate
__(self
, svn_commit_state
)
137 Ctx()._projects
[project_id
] for project_id
in project_ids
140 def get_cvs_items(self
):
143 def get_author(self
):
144 return Ctx().username
146 def get_log_msg(self
):
147 return self
.text_wrapper
.fill(
148 Ctx().initial_project_commit_message
% {}
151 def get_description(self
):
152 return 'Project initialization'
154 def output(self
, output_option
):
155 output_option
.process_initial_project_commit(self
)
158 class SVNRevisionCommit(SVNCommit
):
159 """A SVNCommit that includes actual CVS revisions."""
161 def __init__(self
, cvs_revs
, date
, revnum
):
162 SVNCommit
.__init
__(self
, date
, revnum
)
164 self
.cvs_revs
= list(cvs_revs
)
166 # This value is set lazily by _get_metadata():
167 self
._metadata
= None
169 def __getstate__(self
):
170 """Return the part of the state represented by this mixin."""
173 SVNCommit
.__getstate
__(self
),
174 [cvs_rev
.id for cvs_rev
in self
.cvs_revs
],
177 def __setstate__(self
, state
):
178 """Restore the part of the state represented by this mixin."""
180 (svn_commit_state
, cvs_rev_ids
) = state
181 SVNCommit
.__setstate
__(self
, svn_commit_state
)
185 for (id, cvs_rev
) in Ctx()._cvs
_items
_db
.get_many(cvs_rev_ids
)
187 self
._metadata
= None
189 def get_cvs_items(self
):
192 def _get_metadata(self
):
193 """Return the Metadata instance for this commit."""
195 if self
._metadata
is None:
196 # Set self._metadata for this commit from that of the first cvs
198 if not self
.cvs_revs
:
199 raise InternalError('SVNPrimaryCommit contains no CVS revisions')
201 metadata_id
= self
.cvs_revs
[0].metadata_id
202 self
._metadata
= Ctx()._metadata
_db
[metadata_id
]
204 return self
._metadata
206 def get_author(self
):
207 return self
._get
_metadata
().author
209 def get_warning_summary(self
):
211 retval
.append(SVNCommit
.get_warning_summary(self
) + ' Related files:')
212 for cvs_rev
in self
.cvs_revs
:
213 retval
.append(' ' + cvs_rev
.cvs_file
.filename
)
214 return '\n'.join(retval
)
217 """Return the revision part of a description of this SVNCommit.
219 Derived classes should append the output of this method to the
220 output of SVNCommit.__str__()."""
223 ret
.append(SVNCommit
.__str
__(self
))
224 ret
.append(' cvs_revs:\n')
225 for cvs_rev
in self
.cvs_revs
:
226 ret
.append(' %x\n' % (cvs_rev
.id,))
230 class SVNPrimaryCommit(SVNRevisionCommit
):
231 def __init__(self
, cvs_revs
, date
, revnum
):
232 SVNRevisionCommit
.__init
__(self
, cvs_revs
, date
, revnum
)
234 def get_log_msg(self
):
235 """Return the actual log message for this commit."""
237 return self
._get
_metadata
().log_msg
239 def get_description(self
):
242 def output(self
, output_option
):
243 output_option
.process_primary_commit(self
)
246 class SVNPostCommit(SVNRevisionCommit
):
247 def __init__(self
, motivating_revnum
, cvs_revs
, date
, revnum
):
248 SVNRevisionCommit
.__init
__(self
, cvs_revs
, date
, revnum
)
250 # The subversion revision number of the *primary* commit where the
251 # default branch changes actually happened. (NOTE: Secondary
252 # commits that fill branches and tags also have a motivating
253 # commit, but we do not record it because it is (currently) not
254 # needed for anything.) motivating_revnum is used when generating
255 # the log message for the commit that synchronizes the default
258 # It is possible for multiple synchronization commits to refer to
259 # the same motivating commit revision number, and it is possible
260 # for a single synchronization commit to contain CVSRevisions on
261 # multiple different default branches.
262 self
.motivating_revnum
= motivating_revnum
264 def __getstate__(self
):
266 SVNRevisionCommit
.__getstate
__(self
),
267 self
.motivating_revnum
,
270 def __setstate__(self
, state
):
271 (rev_state
, self
.motivating_revnum
,) = state
272 SVNRevisionCommit
.__setstate
__(self
, rev_state
)
274 def get_cvs_items(self
):
275 # It might seem that we should return
276 # SVNRevisionCommit.get_cvs_items(self) here, but this commit
277 # doesn't really include those CVSItems, but rather followup
281 def get_log_msg(self
):
282 """Return a manufactured log message for this commit."""
284 return self
.text_wrapper
.fill(
285 Ctx().post_commit_message
% {'revnum' : self
.motivating_revnum
}
288 def get_description(self
):
289 return 'post-commit default branch(es)'
291 def output(self
, output_option
):
292 output_option
.process_post_commit(self
)
295 class SVNSymbolCommit(SVNCommit
):
296 def __init__(self
, symbol
, cvs_symbol_ids
, date
, revnum
):
297 SVNCommit
.__init
__(self
, date
, revnum
)
299 # The TypedSymbol that is filled in this SVNCommit.
302 self
.cvs_symbol_ids
= cvs_symbol_ids
304 def __getstate__(self
):
306 SVNCommit
.__getstate
__(self
),
307 self
.symbol
.id, self
.cvs_symbol_ids
,
310 def __setstate__(self
, state
):
311 (svn_commit_state
, symbol_id
, self
.cvs_symbol_ids
) = state
312 SVNCommit
.__setstate
__(self
, svn_commit_state
)
313 self
.symbol
= Ctx()._symbol
_db
.get_symbol(symbol_id
)
315 def get_cvs_items(self
):
319 in Ctx()._cvs
_items
_db
.get_many(self
.cvs_symbol_ids
)
322 def _get_symbol_type(self
):
323 """Return the type of the self.symbol ('branch' or 'tag')."""
325 raise NotImplementedError()
327 def get_author(self
):
328 return Ctx().username
330 def get_log_msg(self
):
331 """Return a manufactured log message for this commit."""
333 return self
.text_wrapper
.fill(
334 Ctx().symbol_commit_message
% {
335 'symbol_type' : self
._get
_symbol
_type
(),
336 'symbol_name' : self
.symbol
.name
,
340 def get_description(self
):
341 return 'copying to %s %r' % (self
._get
_symbol
_type
(), self
.symbol
.name
,)
344 """ Print a human-readable description of this SVNCommit.
346 This description is not intended to be machine-parseable."""
349 SVNCommit
.__str
__(self
)
350 + " symbolic name: %s\n" % (self
.symbol
.name
,)
354 class SVNBranchCommit(SVNSymbolCommit
):
355 def __init__(self
, symbol
, cvs_symbol_ids
, date
, revnum
):
356 if not isinstance(symbol
, Branch
):
357 raise InternalError('Incorrect symbol type %r' % (symbol
,))
359 SVNSymbolCommit
.__init
__(self
, symbol
, cvs_symbol_ids
, date
, revnum
)
361 def _get_symbol_type(self
):
364 def output(self
, output_option
):
365 output_option
.process_branch_commit(self
)
368 class SVNTagCommit(SVNSymbolCommit
):
369 def __init__(self
, symbol
, cvs_symbol_ids
, date
, revnum
):
370 if not isinstance(symbol
, Tag
):
371 raise InternalError('Incorrect symbol type %r' % (symbol
,))
373 SVNSymbolCommit
.__init
__(self
, symbol
, cvs_symbol_ids
, date
, revnum
)
375 def _get_symbol_type(self
):
378 def output(self
, output_option
):
379 output_option
.process_tag_commit(self
)