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."""
23 from context
import Ctx
28 """An artifact that can be created, used across cvs2svn passes, then
31 def __init__(self
, name
):
34 # A map { which_pass : None } of passes that need this artifact.
35 # This field is maintained by ArtifactManager.
36 self
._passes
_needed
= { }
39 """This artifact is no longer needed; clean it up."""
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
)
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.
68 - Call register_artifact() or register_temp_file() for all possible
69 artifacts (even those that should have been created by previous
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).
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
89 - Call check_clean() to verify that all artifacts have been
93 # A map { artifact_name : artifact } of known 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
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."""
152 artifacts
= self
._pass
_needs
[which_pass
].keys()
154 # No artifacts were needed for that pass:
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
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
181 artifacts
= self
._unregister
_artifacts
(which_pass
)
182 if not Ctx().skip_cleanup
:
183 for artifact
in artifacts
:
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
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.)"""
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()