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 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
39 from cvs2svn_lib
.common
import InternalError
40 from cvs2svn_lib
.context
import Ctx
41 from cvs2svn_lib
.symbol
import Branch
42 from cvs2svn_lib
.symbol
import Tag
46 """This represents one commit to the Subversion Repository."""
48 def __init__(self
, date
, revnum
):
49 """Instantiate an SVNCommit.
51 REVNUM is the SVN revision number of this commit."""
53 # The date of the commit, as an integer. While the SVNCommit is
54 # being built up, this contains the latest date seen so far. This
55 # member is set externally.
58 # The SVN revision number of this commit, as an integer.
61 def __getstate__(self
):
62 return (self
.date
, self
.revnum
,)
64 def __setstate__(self
, state
):
65 (self
.date
, self
.revnum
,) = state
67 def get_cvs_items(self
):
68 """Return a list containing the CVSItems in this commit."""
70 raise NotImplementedError()
73 """Return the author or this commit, or None if none is to be used.
75 The return value is exactly as the author appeared in the RCS
76 file, with undefined character encoding."""
78 raise NotImplementedError()
80 def get_log_msg(self
):
81 """Return a log message for this commit.
83 The return value is exactly as the log message appeared in the RCS
84 file, with undefined character encoding."""
86 raise NotImplementedError()
88 def get_warning_summary(self
):
89 """Return a summary of this commit that can be used in warnings."""
91 return '(subversion rev %s)' % (self
.revnum
,)
93 def get_description(self
):
94 """Return a partial description of this SVNCommit, for logging."""
96 raise NotImplementedError()
98 def output(self
, output_option
):
99 """Cause this commit to be output to OUTPUT_OPTION.
101 This method is used for double-dispatch. Derived classes should
102 call the OutputOption.process_*_commit() method appropriate for
103 the type of SVNCommit."""
105 raise NotImplementedError()
108 """ Print a human-readable description of this SVNCommit.
110 This description is not intended to be machine-parseable."""
112 ret
= "SVNCommit #: " + str(self
.revnum
) + "\n"
113 ret
+= " debug description: " + self
.get_description() + "\n"
117 class SVNInitialProjectCommit(SVNCommit
):
118 def __init__(self
, date
, projects
, revnum
):
119 SVNCommit
.__init
__(self
, date
, revnum
)
120 self
.projects
= list(projects
)
122 def __getstate__(self
):
124 SVNCommit
.__getstate
__(self
),
125 [project
.id for project
in self
.projects
],
128 def __setstate__(self
, state
):
129 (svn_commit_state
, project_ids
,) = state
130 SVNCommit
.__setstate
__(self
, svn_commit_state
)
132 Ctx()._projects
[project_id
] for project_id
in project_ids
135 def get_cvs_items(self
):
138 def get_author(self
):
139 return Ctx().username
141 def get_log_msg(self
):
142 return Ctx().text_wrapper
.fill(
143 Ctx().initial_project_commit_message
% {}
146 def get_description(self
):
147 return 'Project initialization'
149 def output(self
, output_option
):
150 output_option
.process_initial_project_commit(self
)
153 class SVNRevisionCommit(SVNCommit
):
154 """A SVNCommit that includes actual CVS revisions."""
156 def __init__(self
, cvs_revs
, date
, revnum
):
157 SVNCommit
.__init
__(self
, date
, revnum
)
159 self
.cvs_revs
= list(cvs_revs
)
161 # This value is set lazily by _get_metadata():
162 self
._metadata
= None
164 def __getstate__(self
):
165 """Return the part of the state represented by this mixin."""
168 SVNCommit
.__getstate
__(self
),
169 [cvs_rev
.id for cvs_rev
in self
.cvs_revs
],
172 def __setstate__(self
, state
):
173 """Restore the part of the state represented by this mixin."""
175 (svn_commit_state
, cvs_rev_ids
) = state
176 SVNCommit
.__setstate
__(self
, svn_commit_state
)
180 for (id, cvs_rev
) in Ctx()._cvs
_items
_db
.get_many(cvs_rev_ids
)
182 self
._metadata
= None
184 def get_cvs_items(self
):
187 def _get_metadata(self
):
188 """Return the Metadata instance for this commit."""
190 if self
._metadata
is None:
191 # Set self._metadata for this commit from that of the first cvs
193 if not self
.cvs_revs
:
194 raise InternalError('SVNPrimaryCommit contains no CVS revisions')
196 metadata_id
= self
.cvs_revs
[0].metadata_id
197 self
._metadata
= Ctx()._metadata
_db
[metadata_id
]
199 return self
._metadata
201 def get_author(self
):
202 return self
._get
_metadata
().author
204 def get_warning_summary(self
):
206 retval
.append(SVNCommit
.get_warning_summary(self
) + ' Related files:')
207 for cvs_rev
in self
.cvs_revs
:
208 retval
.append(' ' + cvs_rev
.cvs_file
.rcs_path
)
209 return '\n'.join(retval
)
212 """Return the revision part of a description of this SVNCommit.
214 Derived classes should append the output of this method to the
215 output of SVNCommit.__str__()."""
218 ret
.append(SVNCommit
.__str
__(self
))
219 ret
.append(' cvs_revs:\n')
220 for cvs_rev
in self
.cvs_revs
:
221 ret
.append(' %x\n' % (cvs_rev
.id,))
225 class SVNPrimaryCommit(SVNRevisionCommit
):
226 def __init__(self
, cvs_revs
, date
, revnum
):
227 SVNRevisionCommit
.__init
__(self
, cvs_revs
, date
, revnum
)
229 def get_log_msg(self
):
230 """Return the actual log message for this commit."""
232 return self
._get
_metadata
().log_msg
234 def get_description(self
):
237 def output(self
, output_option
):
238 output_option
.process_primary_commit(self
)
241 class SVNPostCommit(SVNRevisionCommit
):
242 def __init__(self
, motivating_revnum
, cvs_revs
, date
, revnum
):
243 SVNRevisionCommit
.__init
__(self
, cvs_revs
, date
, revnum
)
245 # The subversion revision number of the *primary* commit where the
246 # default branch changes actually happened. (NOTE: Secondary
247 # commits that fill branches and tags also have a motivating
248 # commit, but we do not record it because it is (currently) not
249 # needed for anything.) motivating_revnum is used when generating
250 # the log message for the commit that synchronizes the default
253 # It is possible for multiple synchronization commits to refer to
254 # the same motivating commit revision number, and it is possible
255 # for a single synchronization commit to contain CVSRevisions on
256 # multiple different default branches.
257 self
.motivating_revnum
= motivating_revnum
259 def __getstate__(self
):
261 SVNRevisionCommit
.__getstate
__(self
),
262 self
.motivating_revnum
,
265 def __setstate__(self
, state
):
266 (rev_state
, self
.motivating_revnum
,) = state
267 SVNRevisionCommit
.__setstate
__(self
, rev_state
)
269 def get_cvs_items(self
):
270 # It might seem that we should return
271 # SVNRevisionCommit.get_cvs_items(self) here, but this commit
272 # doesn't really include those CVSItems, but rather followup
276 def get_log_msg(self
):
277 """Return a manufactured log message for this commit."""
279 return Ctx().text_wrapper
.fill(
280 Ctx().post_commit_message
% {'revnum' : self
.motivating_revnum
}
283 def get_description(self
):
284 return 'post-commit default branch(es)'
286 def output(self
, output_option
):
287 output_option
.process_post_commit(self
)
290 class SVNSymbolCommit(SVNCommit
):
291 def __init__(self
, symbol
, cvs_symbol_ids
, date
, revnum
):
292 SVNCommit
.__init
__(self
, date
, revnum
)
294 # The TypedSymbol that is filled in this SVNCommit.
297 self
.cvs_symbol_ids
= cvs_symbol_ids
299 def __getstate__(self
):
301 SVNCommit
.__getstate
__(self
),
302 self
.symbol
.id, self
.cvs_symbol_ids
,
305 def __setstate__(self
, state
):
306 (svn_commit_state
, symbol_id
, self
.cvs_symbol_ids
) = state
307 SVNCommit
.__setstate
__(self
, svn_commit_state
)
308 self
.symbol
= Ctx()._symbol
_db
.get_symbol(symbol_id
)
310 def get_cvs_items(self
):
314 in Ctx()._cvs
_items
_db
.get_many(self
.cvs_symbol_ids
)
317 def _get_symbol_type(self
):
318 """Return the type of the self.symbol ('branch' or 'tag')."""
320 raise NotImplementedError()
322 def get_author(self
):
323 return Ctx().username
325 def get_log_msg(self
):
326 """Return a manufactured log message for this commit."""
328 return Ctx().text_wrapper
.fill(
329 Ctx().symbol_commit_message
% {
330 'symbol_type' : self
._get
_symbol
_type
(),
331 'symbol_name' : self
.symbol
.name
,
335 def get_description(self
):
336 return 'copying to %s %r' % (self
._get
_symbol
_type
(), self
.symbol
.name
,)
339 """ Print a human-readable description of this SVNCommit.
341 This description is not intended to be machine-parseable."""
344 SVNCommit
.__str
__(self
)
345 + " symbolic name: %s\n" % (self
.symbol
.name
,)
349 class SVNBranchCommit(SVNSymbolCommit
):
350 def __init__(self
, symbol
, cvs_symbol_ids
, date
, revnum
):
351 if not isinstance(symbol
, Branch
):
352 raise InternalError('Incorrect symbol type %r' % (symbol
,))
354 SVNSymbolCommit
.__init
__(self
, symbol
, cvs_symbol_ids
, date
, revnum
)
356 def _get_symbol_type(self
):
359 def output(self
, output_option
):
360 output_option
.process_branch_commit(self
)
363 class SVNTagCommit(SVNSymbolCommit
):
364 def __init__(self
, symbol
, cvs_symbol_ids
, date
, revnum
):
365 if not isinstance(symbol
, Tag
):
366 raise InternalError('Incorrect symbol type %r' % (symbol
,))
368 SVNSymbolCommit
.__init
__(self
, symbol
, cvs_symbol_ids
, date
, revnum
)
370 def _get_symbol_type(self
):
373 def output(self
, output_option
):
374 output_option
.process_tag_commit(self
)