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."""
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.
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
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.
60 def __init__(self
, id, project
, parent_directory
, basename
):
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."""
70 self
.id, self
.project
.id,
71 self
.parent_directory
, self
.basename
,
75 def __setstate__(self
, state
):
78 self
.parent_directory
, self
.basename
,
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."""
93 p
= p
.parent_directory
98 def get_cvs_path(self
):
99 """Return the canonical path within the Project.
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:]]
127 """Compare two CVSPath instances for equality.
129 This method is supplied to avoid using __cmp__() for comparing for
134 def slow_compare(a
, b
):
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
())
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.
153 id -- (int or None) unique id for this file. If None, a new id is
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
189 self
.parent_directory
.get_filename(), self
.basename
192 filename
= property(get_filename
)
194 def __getstate__(self
):
196 CVSPath
.__getstate
__(self
),
197 self
.empty_subdirectory_ids
,
200 def __setstate__(self
, state
):
203 self
.empty_subdirectory_ids
,
205 CVSPath
.__setstate
__(self
, cvs_path_state
)
208 """For convenience only. The format is subject to change at any time."""
210 return self
.cvs_path
+ '/'
213 return 'CVSDirectory<%x>(%r)' % (self
.id, str(self
),)
216 class CVSFile(CVSPath
):
217 """Represent a CVS file.
221 id -- (int) unique id for this file.
223 project -- (Project) the project containing this file.
225 parent_directory -- (CVSDirectory) the CVSDirectory containing
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.
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
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."""
279 self
.parent_directory
.filename
, 'Attic', self
.basename
+ ',v'
283 self
.parent_directory
.filename
, self
.basename
+ ',v'
286 filename
= property(get_filename
)
288 def __getstate__(self
):
290 CVSPath
.__getstate
__(self
),
291 self
._in
_attic
, self
.executable
, self
.file_size
, self
.mode
,
295 def __setstate__(self
, state
):
298 self
._in
_attic
, self
.executable
, self
.file_size
, self
.mode
,
301 CVSPath
.__setstate
__(self
, cvs_path_state
)
304 """For convenience only. The format is subject to change at any time."""
309 return 'CVSFile<%x>(%r)' % (self
.id, str(self
),)