Skip to content

Commit b9639a9

Browse files
authored
Feature: Implement profile reset. (#66)
1 parent 76000bb commit b9639a9

File tree

3 files changed

+75
-7
lines changed

3 files changed

+75
-7
lines changed

aiidalab_launch/__main__.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import socket
1111
from dataclasses import dataclass, field
1212
from pathlib import Path
13+
from shutil import rmtree
1314
from textwrap import wrap
1415

1516
import click
@@ -25,7 +26,13 @@
2526
Config,
2627
Profile,
2728
)
28-
from .util import get_docker_client, get_latest_version, spinner, webbrowser_available
29+
from .util import (
30+
confirm_with_value,
31+
get_docker_client,
32+
get_latest_version,
33+
spinner,
34+
webbrowser_available,
35+
)
2936
from .version import __version__
3037

3138
MSG_MOUNT_POINT_CONFLICT = """Warning: There is at least one other running
@@ -638,5 +645,62 @@ def exec(ctx, profile, cmd, privileged, forward_exit_code, wait):
638645
ctx.fail(f"Command failed with exit code: {result['ExitCode']}")
639646

640647

648+
@cli.command()
649+
@click.option(
650+
"--apps",
651+
is_flag=True,
652+
help="Only remove installed apps. The default apps will be installed on the next instance start.",
653+
)
654+
@click.option("--yes", is_flag=True, help="Do not ask for confirmation.")
655+
@with_profile
656+
@pass_app_state
657+
def reset(app_state, profile, apps, yes):
658+
"""Reset an AiiDAlab instance."""
659+
# Check (and abort) in case that the instance is running.
660+
instance = AiidaLabInstance(client=app_state.docker_client, profile=profile)
661+
status = asyncio.run(instance.status())
662+
if status not in (
663+
instance.AiidaLabInstanceStatus.DOWN,
664+
instance.AiidaLabInstanceStatus.CREATED,
665+
instance.AiidaLabInstanceStatus.EXITED,
666+
):
667+
raise click.ClickException(
668+
f"The instance associated with profile '{profile.name}' "
669+
"is still running. Please stop it prior to reset."
670+
)
671+
672+
click.secho(
673+
f"Resetting instance for profile '{profile.name}'. This action cannot be undone!",
674+
err=True,
675+
fg="red",
676+
)
677+
678+
if not yes:
679+
confirm_with_value(
680+
profile.name, "Please enter the name of the profile to continue", abort=True
681+
)
682+
683+
def rmtree_(path: Path) -> None:
684+
if path.exists():
685+
try:
686+
rmtree(path)
687+
except Exception as error:
688+
raise click.ClickException(
689+
f"Encountered error while trying to remove '{path}': {error}"
690+
)
691+
692+
if apps:
693+
click.echo(
694+
"Removing apps directory. Default apps will be installed on next start."
695+
)
696+
rmtree_(Path(profile.home_dir) / "apps")
697+
else:
698+
click.echo("Removing container and associated volumes.")
699+
instance.remove()
700+
701+
click.echo(f"Removing home directory '{profile.home_mount}'.")
702+
rmtree_(Path(profile.home_mount))
703+
704+
641705
if __name__ == "__main__":
642706
cli()

aiidalab_launch/core.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -279,15 +279,10 @@ def stop(self, timeout: Optional[float] = None) -> None:
279279
raise RuntimeError("no container")
280280

281281
def remove(self) -> None:
282-
self._requires_container()
283-
assert self.container is not None
284-
285282
# Remove container
286-
try:
283+
if self.container:
287284
self.container.remove()
288285
self._container = None
289-
except AttributeError:
290-
raise RuntimeError("no container")
291286

292287
# Remove conda volume
293288
try:

aiidalab_launch/util.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,12 @@ def get_latest_version(timeout: float = 0.1) -> Optional[Version]:
147147
except OSError as error:
148148
logging.debug(f"Error while requesting latest version: {error}")
149149
return None
150+
151+
152+
def confirm_with_value(value: str, text: str, abort: bool = False) -> bool:
153+
if click.prompt(text, default="", show_default=False) == value:
154+
return True
155+
elif abort:
156+
raise click.Abort
157+
else:
158+
return False

0 commit comments

Comments
 (0)