Delegate to FilterSink methods rather than reimplementing them.
[cvs2svn.git] / cvs2svn_lib / cvs_path.py
blob9f08dd57375ff1242abe478c1f1f72c97c05a94a
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 """Classes that represent files and directories within CVS repositories."""
19 import os
21 from cvs2svn_lib.common import path_join
22 from cvs2svn_lib.context import Ctx
25 class CVSPath(object):
26 """Represent a CVS file or directory.
28 Members:
30 id -- (int) unique ID for this CVSPath. At any moment, there is
31 at most one CVSPath instance with a particular ID. (This
32 means that object identity is the same as object equality, and
33 objects can be used as map keys even though they don't have a
34 __hash__() method).
36 project -- (Project) the project containing this CVSPath.
38 parent_directory -- (CVSDirectory or None) the CVSDirectory
39 containing this CVSPath.
41 basename -- (string) the base name of this CVSPath (no ',v'). The
42 basename of the root directory of a project is ''.
44 ordinal -- (int) the order that this instance should be sorted
45 relative to other CVSPath instances. This member is set based
46 on the ordering imposed by slow_compare() by CollectData after
47 all CVSFiles have been processed. Comparisons of CVSPath
48 using __cmp__() simply compare the ordinals.
50 """
52 __slots__ = [
53 'id',
54 'project',
55 'parent_directory',
56 'basename',
57 'ordinal',
60 def __init__(self, id, project, parent_directory, basename):
61 self.id = id
62 self.project = project
63 self.parent_directory = parent_directory
64 self.basename = basename
66 def __getstate__(self):
67 """This method must only be called after ordinal has been set."""
69 return (
70 self.id, self.project.id,
71 self.parent_directory, self.basename,
72 self.ordinal,
75 def __setstate__(self, state):
77 self.id, project_id,
78 self.parent_directory, self.basename,
79 self.ordinal,
80 ) = state
81 self.project = Ctx()._projects[project_id]
83 def get_ancestry(self):
84 """Return a list of the CVSPaths leading from the root path to SELF.
86 Return the CVSPaths in a list, starting with
87 self.project.get_root_cvs_directory() and ending with self."""
89 ancestry = []
90 p = self
91 while p is not None:
92 ancestry.append(p)
93 p = p.parent_directory
95 ancestry.reverse()
96 return ancestry
98 def get_cvs_path(self):
99 """Return the canonical path within the Project.
101 The canonical path:
103 - Uses forward slashes
105 - Doesn't include ',v' for files
107 - This doesn't include the 'Attic' segment of the path unless the
108 file is to be left in an Attic directory in the SVN repository;
109 i.e., if a filename exists in and out of Attic and the
110 --retain-conflicting-attic-files option was specified.
114 return path_join(*[p.basename for p in self.get_ancestry()[1:]])
116 cvs_path = property(get_cvs_path)
118 def _get_dir_components(self):
119 """Return a list containing the components of the path leading to SELF.
121 The return value contains the base names of all of the parent
122 directories (except for the root directory) and SELF."""
124 return [p.basename for p in self.get_ancestry()[1:]]
126 def __eq__(a, b):
127 """Compare two CVSPath instances for equality.
129 This method is supplied to avoid using __cmp__() for comparing for
130 equality."""
132 return a is b
134 def slow_compare(a, b):
135 return (
136 # Sort first by project:
137 cmp(a.project, b.project)
138 # Then by directory components:
139 or cmp(a._get_dir_components(), b._get_dir_components())
142 def __cmp__(a, b):
143 """This method must only be called after ordinal has been set."""
145 return cmp(a.ordinal, b.ordinal)
148 class CVSDirectory(CVSPath):
149 """Represent a CVS directory.
151 Members:
153 id -- (int or None) unique id for this file. If None, a new id is
154 generated.
156 project -- (Project) the project containing this file.
158 parent_directory -- (CVSDirectory or None) the CVSDirectory
159 containing this CVSDirectory.
161 basename -- (string) the base name of this CVSDirectory (no ',v').
163 ordinal -- (int) the order that this instance should be sorted
164 relative to other CVSPath instances. See CVSPath.ordinal.
166 empty_subdirectory_ids -- (list of int) a list of the ids of any
167 direct subdirectories that are empty. (An empty directory is
168 defined to be a directory that doesn't contain any RCS files
169 or non-empty subdirectories.
173 __slots__ = ['empty_subdirectory_ids']
175 def __init__(self, id, project, parent_directory, basename):
176 """Initialize a new CVSDirectory object."""
178 CVSPath.__init__(self, id, project, parent_directory, basename)
179 # This member is filled in by CollectData.close():
180 self.empty_subdirectory_ids = []
182 def get_filename(self):
183 """Return the filesystem path to this CVSPath in the CVS repository."""
185 if self.parent_directory is None:
186 return self.project.project_cvs_repos_path
187 else:
188 return os.path.join(
189 self.parent_directory.get_filename(), self.basename
192 filename = property(get_filename)
194 def __getstate__(self):
195 return (
196 CVSPath.__getstate__(self),
197 self.empty_subdirectory_ids,
200 def __setstate__(self, state):
202 cvs_path_state,
203 self.empty_subdirectory_ids,
204 ) = state
205 CVSPath.__setstate__(self, cvs_path_state)
207 def __str__(self):
208 """For convenience only. The format is subject to change at any time."""
210 return self.cvs_path + '/'
212 def __repr__(self):
213 return 'CVSDirectory<%x>(%r)' % (self.id, str(self),)
216 class CVSFile(CVSPath):
217 """Represent a CVS file.
219 Members:
221 id -- (int) unique id for this file.
223 project -- (Project) the project containing this file.
225 parent_directory -- (CVSDirectory) the CVSDirectory containing
226 this CVSFile.
228 basename -- (string) the base name of this CVSFile (no ',v').
230 ordinal -- (int) the order that this instance should be sorted
231 relative to other CVSPath instances. See CVSPath.ordinal.
233 _in_attic -- (bool) True if RCS file is in an Attic subdirectory
234 that is not considered the parent directory. (If a file is
235 in-and-out-of-attic and one copy is to be left in Attic after
236 the conversion, then the Attic directory is that file's
237 PARENT_DIRECTORY and _IN_ATTIC is False.)
239 executable -- (bool) True iff RCS file has executable bit set.
241 file_size -- (long) size of the RCS file in bytes.
243 mode -- (string or None) 'kkv', 'kb', etc.
245 PARENT_DIRECTORY might contain an 'Attic' component if it should be
246 retained in the SVN repository; i.e., if the same filename exists out
247 of Attic and the --retain-conflicting-attic-files option was specified.
251 __slots__ = [
252 '_in_attic',
253 'executable',
254 'file_size',
255 'mode',
256 'description'
259 def __init__(
260 self, id, project, parent_directory, basename, in_attic,
261 executable, file_size, mode, description
263 """Initialize a new CVSFile object."""
265 CVSPath.__init__(self, id, project, parent_directory, basename)
266 self._in_attic = in_attic
267 self.executable = executable
268 self.file_size = file_size
269 self.mode = mode
270 self.description = description
272 assert self.parent_directory is not None
274 def get_filename(self):
275 """Return the filesystem path to this CVSPath in the CVS repository."""
277 if self._in_attic:
278 return os.path.join(
279 self.parent_directory.filename, 'Attic', self.basename + ',v'
281 else:
282 return os.path.join(
283 self.parent_directory.filename, self.basename + ',v'
286 filename = property(get_filename)
288 def __getstate__(self):
289 return (
290 CVSPath.__getstate__(self),
291 self._in_attic, self.executable, self.file_size, self.mode,
292 self.description
295 def __setstate__(self, state):
297 cvs_path_state,
298 self._in_attic, self.executable, self.file_size, self.mode,
299 self.description
300 ) = state
301 CVSPath.__setstate__(self, cvs_path_state)
303 def __str__(self):
304 """For convenience only. The format is subject to change at any time."""
306 return self.cvs_path
308 def __repr__(self):
309 return 'CVSFile<%x>(%r)' % (self.id, str(self),)