1515from snakemake_interface_software_deployment_plugins .settings import (
1616 SoftwareDeploymentSettingsBase ,
1717)
18+ from snakemake_interface_common .exceptions import WorkflowError
1819
1920
2021@dataclass
@@ -116,6 +117,11 @@ def __eq__(self, other) -> bool:
116117 for attr in self .managed_identity_attributes ()
117118 )
118119
120+ @abstractmethod
121+ def __str__ (self ) -> str :
122+ """Return a string representation of the environment spec."""
123+ ...
124+
119125
120126class EnvBase (ABC ):
121127 _cache : Dict [Tuple [Type ["EnvBase" ], Optional ["EnvBase" ]], Any ] = {}
@@ -128,7 +134,7 @@ def __init__(
128134 shell_executable : str ,
129135 tempdir : Path ,
130136 deployment_prefix : Optional [Path ] = None ,
131- archive_prefix : Optional [Path ] = None ,
137+ cache_prefix : Optional [Path ] = None ,
132138 ):
133139 self .spec : EnvSpecBase = spec
134140 self .within : Optional ["EnvBase" ] = within
@@ -139,7 +145,7 @@ def __init__(
139145 self ._managed_deployment_hash_store : Optional [str ] = None
140146 self ._obj_hash : Optional [int ] = None
141147 self ._deployment_prefix : Optional [Path ] = deployment_prefix
142- self ._archive_prefix : Optional [Path ] = archive_prefix
148+ self ._cache_prefix : Optional [Path ] = cache_prefix
143149 self .__post_init__ ()
144150
145151 def __post_init__ (self ) -> None : # noqa B027
@@ -237,6 +243,12 @@ class DeployableEnvBase(ABC):
237243 @abstractmethod
238244 def is_deployment_path_portable (self ) -> bool : ...
239245
246+ async def cache (self ) -> None :
247+ """Determine environment assets and store any associated information to
248+ self.cache_path.
249+ """
250+ ...
251+
240252 @abstractmethod
241253 async def deploy (self ) -> None :
242254 """Deploy the environment to self.deployment_path.
@@ -264,11 +276,35 @@ def remove(self) -> None:
264276 """Remove the deployed environment."""
265277 ...
266278
279+ def managed_remove (self ) -> None :
280+ """Remove the deployed environment, handling exceptions."""
281+ assert isinstance (self , EnvBase )
282+ try :
283+ self .remove ()
284+ except Exception as e :
285+ raise WorkflowError (
286+ f"Removal of { self .spec } failed: { e } "
287+ )
288+
289+ def remove_cache (self ) -> None :
290+ """Remove the cached environment assets."""
291+ assert isinstance (self , EnvBase )
292+ if self .cache_path .exists ():
293+ try :
294+ shutil .rmtree (self .cache_path )
295+ except Exception as e :
296+ raise WorkflowError (
297+ f"Removal of cache for { self .spec } failed: { e } "
298+ )
299+
267300 async def managed_deploy (self ) -> None :
268- if isinstance (self , ArchiveableEnvBase ) and self .archive_path .exists ():
269- await self .deploy_from_archive ()
270- else :
301+ assert isinstance (self , EnvBase )
302+ try :
271303 await self .deploy ()
304+ except Exception as e :
305+ raise WorkflowError (
306+ f"Deployment of { self .spec } failed: { e } "
307+ )
272308
273309 def deployment_hash (self ) -> str :
274310 assert isinstance (self , EnvBase )
@@ -279,35 +315,7 @@ def deployment_path(self) -> Path:
279315 assert isinstance (self , EnvBase ) and self ._deployment_prefix is not None
280316 return self ._deployment_prefix / self .deployment_hash ()
281317
282-
283- class ArchiveableEnvBase (ABC ):
284- @abstractmethod
285- async def archive (self ) -> None :
286- """Archive the environment to self.archive_path.
287-
288- When issuing shell commands, the environment should use
289- self.run_cmd(cmd: str) in order to ensure that it runs within eventual
290- parent environments (e.g. a container or an env module).
291- """
292- ...
293-
294- @abstractmethod
295- async def deploy_from_archive (self ) -> None :
296- """Deploy the environment from self.archive_path to self.deployment_path.
297-
298- When issuing shell commands, the environment should use
299- self.run_cmd(cmd: str) in order to ensure that it runs within eventual
300- parent environments (e.g. a container or an env module).
301- """
302- ...
303-
304318 @property
305- def archive_path (self ) -> Path :
306- assert isinstance (self , EnvBase ) and self ._archive_prefix is not None
307- return self ._archive_prefix / self .hash ()
308-
309- def remove_archive (self ) -> None :
310- """Remove the archived environment."""
311- if self .archive_path .exists ():
312- # remove the archive directory
313- shutil .rmtree (self .archive_path , ignore_errors = True )
319+ def cache_path (self ) -> Path :
320+ assert isinstance (self , EnvBase ) and self ._cache_prefix is not None
321+ return self ._cache_prefix / self .hash ()
0 commit comments