Don't delete chunk files in merge().
[cvs2svn.git] / cvs2svn_lib / cvs_file.py
blob2a42b1aca0bfc71d75477a9536dc20e298e94f80
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 a class to store information about a CVS file."""
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').
165 __slots__ = []
167 def __init__(self, id, project, parent_directory, basename):
168 """Initialize a new CVSDirectory object."""
170 CVSPath.__init__(self, id, project, parent_directory, basename)
172 def get_filename(self):
173 """Return the filesystem path to this CVSPath in the CVS repository."""
175 if self.parent_directory is None:
176 return self.project.project_cvs_repos_path
177 else:
178 return os.path.join(
179 self.parent_directory.get_filename(), self.basename
182 filename = property(get_filename)
184 def __getstate__(self):
185 return CVSPath.__getstate__(self)
187 def __setstate__(self, state):
188 CVSPath.__setstate__(self, state)
190 def __str__(self):
191 """For convenience only. The format is subject to change at any time."""
193 return self.cvs_path + '/'
195 def __repr__(self):
196 return 'CVSDirectory<%x>(%r)' % (self.id, str(self),)
199 class CVSFile(CVSPath):
200 """Represent a CVS file.
202 Members:
204 id -- (int) unique id for this file.
206 project -- (Project) the project containing this file.
208 parent_directory -- (CVSDirectory) the CVSDirectory containing
209 this CVSFile.
211 basename -- (string) the base name of this CVSFile (no ',v').
213 _in_attic -- (bool) True if RCS file is in an Attic subdirectory
214 that is not considered the parent directory. (If a file is
215 in-and-out-of-attic and one copy is to be left in Attic after
216 the conversion, then the Attic directory is that file's
217 PARENT_DIRECTORY and _IN_ATTIC is False.)
219 executable -- (bool) True iff RCS file has executable bit set.
221 file_size -- (long) size of the RCS file in bytes.
223 mode -- (string or None) 'kkv', 'kb', etc.
225 PARENT_DIRECTORY might contain an 'Attic' component if it should be
226 retained in the SVN repository; i.e., if the same filename exists out
227 of Attic and the --retain-conflicting-attic-files option was specified.
231 __slots__ = [
232 '_in_attic',
233 'executable',
234 'file_size',
235 'mode',
236 'description'
239 def __init__(
240 self, id, project, parent_directory, basename, in_attic,
241 executable, file_size, mode, description
243 """Initialize a new CVSFile object."""
245 CVSPath.__init__(self, id, project, parent_directory, basename)
246 self._in_attic = in_attic
247 self.executable = executable
248 self.file_size = file_size
249 self.mode = mode
250 self.description = description
252 assert self.parent_directory is not None
254 def get_filename(self):
255 """Return the filesystem path to this CVSPath in the CVS repository."""
257 if self._in_attic:
258 return os.path.join(
259 self.parent_directory.filename, 'Attic', self.basename + ',v'
261 else:
262 return os.path.join(
263 self.parent_directory.filename, self.basename + ',v'
266 filename = property(get_filename)
268 def __getstate__(self):
269 return (
270 CVSPath.__getstate__(self),
271 self._in_attic, self.executable, self.file_size, self.mode, self.description
274 def __setstate__(self, state):
276 cvs_path_state,
277 self._in_attic, self.executable, self.file_size, self.mode, self.description
278 ) = state
279 CVSPath.__setstate__(self, cvs_path_state)
281 def __str__(self):
282 """For convenience only. The format is subject to change at any time."""
284 return self.cvs_path
286 def __repr__(self):
287 return 'CVSFile<%x>(%r)' % (self.id, str(self),)