feat(instance_manager): add interactive stopping of Klipper instances (#784)

* feat(instance_manager): add interactive stopping of Klipper instances with user confirmation

* fix(instance_utils): remove unnecessary 'self' parameter from stop_klipper_instances_interactively function

* refactor(tmc_autotune): replace internal stop function with direct call to stop_klipper_instances_interactively
This commit is contained in:
Théo Gaillard
2026-03-22 12:01:15 +01:00
committed by GitHub
parent 308079a821
commit 7ca08f9b30
2 changed files with 45 additions and 41 deletions

View File

@@ -30,7 +30,7 @@ from utils.config_utils import add_config_section, remove_config_section
from utils.fs_utils import check_file_exist, create_symlink, run_remove_routines from utils.fs_utils import check_file_exist, create_symlink, run_remove_routines
from utils.git_utils import git_clone_wrapper, git_pull_wrapper from utils.git_utils import git_clone_wrapper, git_pull_wrapper
from utils.input_utils import get_confirm from utils.input_utils import get_confirm
from utils.instance_utils import get_instances from utils.instance_utils import get_instances, stop_klipper_instances_interactively
from utils.sys_utils import check_python_version from utils.sys_utils import check_python_version
@@ -84,7 +84,7 @@ class TmcAutotuneExtension(BaseExtension):
kl_instances = get_instances(Klipper) kl_instances = get_instances(Klipper)
if not self._stop_klipper_instances_interactively( if not stop_klipper_instances_interactively(
kl_instances, "installation of TMC Autotune" kl_instances, "installation of TMC Autotune"
): ):
return return
@@ -172,7 +172,7 @@ class TmcAutotuneExtension(BaseExtension):
kl_instances = get_instances(Klipper) kl_instances = get_instances(Klipper)
if not self._stop_klipper_instances_interactively( if not stop_klipper_instances_interactively(
kl_instances, "update of TMC Autotune" kl_instances, "update of TMC Autotune"
): ):
return return
@@ -210,7 +210,7 @@ class TmcAutotuneExtension(BaseExtension):
kl_instances = get_instances(Klipper) kl_instances = get_instances(Klipper)
if not self._stop_klipper_instances_interactively( if not stop_klipper_instances_interactively(
kl_instances, "removal of TMC Autotune" kl_instances, "removal of TMC Autotune"
): ):
return return
@@ -345,40 +345,3 @@ class TmcAutotuneExtension(BaseExtension):
"Klipper TMC Autotune successfully removed from Moonraker update manager(s)!" "Klipper TMC Autotune successfully removed from Moonraker update manager(s)!"
) )
def _stop_klipper_instances_interactively(
self, kl_instances: List[Klipper], operation_name: str = "operation"
) -> bool:
"""
Interactively stops all active Klipper instances, warning the user that ongoing prints will be disrupted.
:param kl_instances: List of Klipper instances to stop.
:param operation_name: Optional name of the operation being performed (for user messaging). Do NOT capitalize.
:return: True if instances were stopped or no instances found, False if operation was aborted.
"""
if not kl_instances:
Logger.print_warn("No instances found, skipping instance stopping.")
return True
Logger.print_dialog(
DialogType.ATTENTION,
[
"Do NOT continue if there are ongoing prints running",
f"All Klipper instances will be restarted during the {operation_name} and "
"ongoing prints WILL FAIL.",
],
)
stop_klipper = get_confirm(
question=f"Stop Klipper now and proceed with {operation_name}?",
default_choice=False,
allow_go_back=True,
)
if stop_klipper:
InstanceManager.stop_all(kl_instances)
return True
else:
Logger.print_warn(
f"{operation_name.capitalize()} aborted due to user request."
)
return False

View File

@@ -12,8 +12,12 @@ import re
from pathlib import Path from pathlib import Path
from typing import List from typing import List
from components.klipper.klipper import Klipper
from core.constants import SYSTEMD from core.constants import SYSTEMD
from core.instance_manager.base_instance import SUFFIX_BLACKLIST from core.instance_manager.base_instance import SUFFIX_BLACKLIST
from core.instance_manager.instance_manager import InstanceManager
from core.logger import DialogType, Logger
from utils.input_utils import get_confirm
from utils.instance_type import InstanceType from utils.instance_type import InstanceType
@@ -56,3 +60,40 @@ def get_instance_suffix(name: str, file_path: Path) -> str:
# otherwise there is and hyphen left, and we return the part after the hyphen # otherwise there is and hyphen left, and we return the part after the hyphen
suffix = file_path.stem[len(name) :] suffix = file_path.stem[len(name) :]
return suffix[1:] if suffix else "" return suffix[1:] if suffix else ""
def stop_klipper_instances_interactively(
kl_instances: List[Klipper], operation_name: str = "operation"
) -> bool:
"""
Interactively stops all active Klipper instances, warning the user that ongoing prints will be disrupted.
:param kl_instances: List of Klipper instances to stop.
:param operation_name: Optional name of the operation being performed (for user messaging). Do NOT capitalize.
:return: True if instances were stopped or no instances found, False if operation was aborted.
"""
if not kl_instances:
Logger.print_warn("No instances found, skipping instance stopping.")
return True
Logger.print_dialog(
DialogType.ATTENTION,
[
"Do NOT continue if there are ongoing prints running",
f"All Klipper instances will be restarted during the {operation_name} and "
"ongoing prints WILL FAIL.",
],
)
stop_klipper = get_confirm(
question=f"Stop Klipper now and proceed with {operation_name}?",
default_choice=False,
allow_go_back=True,
)
if stop_klipper:
InstanceManager.stop_all(kl_instances)
return True
else:
Logger.print_warn(f"{operation_name.capitalize()} aborted due to user request.")
return False