Skip to content

Commit 62be1da

Browse files
migrate archive into cache semantics
1 parent 617189c commit 62be1da

1 file changed

Lines changed: 44 additions & 36 deletions

File tree

  • snakemake_interface_software_deployment_plugins

snakemake_interface_software_deployment_plugins/__init__.py

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from 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

120126
class 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

Comments
 (0)