Give each pass object a name.
[cvs2svn.git] / cvs2svn_lib / artifact_manager.py
bloba26eb9bac24871a19c40a9191d84698578ec7077
1 # (Be in -*- python -*- mode.)
3 # ====================================================================
4 # Copyright (c) 2000-2006 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 manages the artifacts produced by conversion passes."""
20 import os
22 from boolean import *
23 from context import Ctx
24 from log import Log
27 class Artifact:
28 """An artifact that can be created, used across cvs2svn passes, then
29 cleaned up."""
31 def __init__(self, name):
32 self.name = name
34 # A map { which_pass : None } of passes that need this artifact.
35 # This field is maintained by ArtifactManager.
36 self._passes_needed = { }
38 def cleanup(self):
39 """This artifact is no longer needed; clean it up."""
41 pass
43 def __str__(self):
44 return self.name
47 class TempFileArtifact(Artifact):
48 """A temporary file that can be used across cvs2svn passes."""
50 def __init__(self, basename):
51 Artifact.__init__(self, basename)
52 self.filename = Ctx().get_temp_filename(basename)
54 def cleanup(self):
55 Log().write(Log.VERBOSE, "Deleting", self.filename)
56 os.unlink(self.filename)
59 class ArtifactManager:
60 """Manager artifacts that are created by one pass but needed by others.
62 This class is responsible for cleaning up artifacts once they are no
63 longer needed. The trick is that cvs2svn can be run pass by pass,
64 so not all passes might be executed during a specific program run.
66 To use this class:
68 - Call register_artifact() or register_temp_file() for all possible
69 artifacts (even those that should have been created by previous
70 cvs2svn runs).
72 - Call register_artifact_needed() or register_temp_file_needed() for
73 any artifact that are needed by any pass (even those passes that
74 won't be executed during this cvs2svn run).
76 Then, in pass order:
78 - Call pass_skipped() for any passes that were already executed
79 during a previous cvs2svn run.
81 - Call pass_done() after a pass is executed, to allow any artifacts
82 that won't be needed anymore to be cleaned up.
84 - Call pass_deferred() for any passes that have been deferred to a
85 future cvs2svn run.
87 Finally:
89 - Call check_clean() to verify that all artifacts have been
90 accounted for."""
92 def __init__(self):
93 # A map { artifact_name : artifact } of known artifacts.
94 self._artifacts = { }
96 # A map { pass : set_of_artifacts }, where set_of_artifacts is a
97 # map { artifact : None } of artifacts needed by the pass.
98 self._pass_needs = { }
100 def register_artifact(self, artifact, which_pass):
101 """Register a new ARTIFACT for management by this class.
102 WHICH_PASS is the pass that creates ARTIFACT, and is also assumed
103 to need it. It is an error to registier the same artifact more
104 than once."""
106 assert artifact.name not in self._artifacts
107 self._artifacts[artifact.name] = artifact
108 self.register_artifact_needed(artifact.name, which_pass)
110 def register_temp_file(self, basename, which_pass):
111 """Register a temporary file with base name BASENAME as an
112 artifact. Return the filename of the temporary file."""
114 artifact = TempFileArtifact(basename)
115 self.register_artifact(artifact, which_pass)
116 return artifact.filename
118 def get_artifact(self, artifact_name):
119 """Return the artifact with the specified name. If the artifact
120 does not currently exist, raise a KeyError."""
122 return self._artifacts[artifact_name]
124 def get_temp_file(self, basename):
125 """Return the filename of the temporary file with the specified BASENAME.
127 If the temporary file is not an existing, registered
128 TempFileArtifact, raise a KeyError."""
130 return self.get_artifact(basename).filename
132 def register_artifact_needed(self, artifact_name, which_pass):
133 """Register that WHICH_PASS needs the artifact named ARTIFACT_NAME.
134 An artifact with this name must already have been registered."""
136 artifact = self.get_artifact(artifact_name)
137 artifact._passes_needed[which_pass] = None
138 self._pass_needs.setdefault(which_pass, {})[artifact] = None
140 def register_temp_file_needed(self, basename, which_pass):
141 """Register that the temporary file with base name BASENAME is
142 needed by WHICH_PASS."""
144 self.register_artifact_needed(basename, which_pass)
146 def _unregister_artifacts(self, which_pass):
147 """Unregister any artifacts that were needed for WHICH_PASS.
149 Return a list of artifacts that are no longer needed at all."""
151 try:
152 artifacts = self._pass_needs[which_pass].keys()
153 except KeyError:
154 # No artifacts were needed for that pass:
155 return []
157 del self._pass_needs[which_pass]
159 unneeded_artifacts = []
160 for artifact in artifacts:
161 del artifact._passes_needed[which_pass]
162 if not artifact._passes_needed:
163 del self._artifacts[artifact.name]
164 unneeded_artifacts.append(artifact)
166 return unneeded_artifacts
168 def pass_skipped(self, which_pass):
169 """WHICH_PASS was executed during a previous cvs2svn run.
171 Its artifacts were created then, and any artifacts that would
172 normally be cleaned up after this pass have already been cleaned
173 up."""
175 self._unregister_artifacts(which_pass)
177 def pass_done(self, which_pass):
178 """WHICH_PASS is done. Clean up all artifacts that are no longer
179 needed."""
181 artifacts = self._unregister_artifacts(which_pass)
182 if not Ctx().skip_cleanup:
183 for artifact in artifacts:
184 artifact.cleanup()
186 def pass_deferred(self, which_pass):
187 """WHICH_PASS is being deferred until a future cvs2svn run.
188 Unregister any artifacts that would be cleaned up during
189 WHICH_PASS."""
191 self._unregister_artifacts(which_pass)
193 def check_clean(self):
194 """All passes have been processed. Output a warning messages if
195 all artifacts have not been accounted for. (This is mainly a
196 consistency check, that no artifacts were registered under
197 nonexistent passes.)"""
199 if self._artifacts:
200 Log().write(
201 Log.WARN,
202 'INTERNAL: The following artifacts were not cleaned up:\n %s\n'
203 % ('\n '.join([artifact.name for artifact in self._artifacts])))
206 # The default ArtifactManager instance:
207 artifact_manager = ArtifactManager()