machineconfig 2.2__py3-none-any.whl → 2.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of machineconfig might be problematic. Click here for more details.
- machineconfig/__init__.py +30 -0
- machineconfig/cluster/sessions_managers/enhanced_command_runner.py +0 -2
- machineconfig/cluster/sessions_managers/layout_types.py +29 -0
- machineconfig/cluster/sessions_managers/wt_local.py +68 -62
- machineconfig/cluster/sessions_managers/wt_local_manager.py +51 -22
- machineconfig/cluster/sessions_managers/wt_remote.py +30 -108
- machineconfig/cluster/sessions_managers/wt_remote_manager.py +14 -11
- machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +33 -37
- machineconfig/cluster/sessions_managers/wt_utils/process_monitor.py +22 -17
- machineconfig/cluster/sessions_managers/wt_utils/session_manager.py +59 -10
- machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +16 -14
- machineconfig/cluster/sessions_managers/zellij_local.py +75 -57
- machineconfig/cluster/sessions_managers/zellij_local_manager.py +51 -23
- machineconfig/cluster/sessions_managers/zellij_remote.py +47 -27
- machineconfig/cluster/sessions_managers/zellij_remote_manager.py +13 -12
- machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +14 -10
- machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +31 -15
- machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +47 -21
- machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +1 -1
- machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +8 -7
- machineconfig/cluster/templates/utils.py +1 -1
- machineconfig/profile/create.py +4 -0
- machineconfig/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/linux/checkout_versions +1 -7
- machineconfig/scripts/linux/choose_wezterm_theme +1 -7
- machineconfig/scripts/linux/cloud_copy +1 -8
- machineconfig/scripts/linux/cloud_manager +1 -7
- machineconfig/scripts/linux/cloud_mount +1 -23
- machineconfig/scripts/linux/cloud_repo_sync +1 -21
- machineconfig/scripts/linux/cloud_sync +1 -23
- machineconfig/scripts/linux/croshell +1 -23
- machineconfig/scripts/linux/devops +0 -21
- machineconfig/scripts/linux/fire +1 -27
- machineconfig/scripts/linux/fire_agents +1 -26
- machineconfig/scripts/linux/gh_models +1 -10
- machineconfig/scripts/linux/kill_process +1 -9
- machineconfig/scripts/linux/mcinit +1 -26
- machineconfig/scripts/linux/mount_nfs +1 -13
- machineconfig/scripts/linux/repos +1 -23
- machineconfig/scripts/linux/scheduler +1 -7
- machineconfig/scripts/linux/start_slidev +1 -22
- machineconfig/scripts/linux/start_terminals +1 -9
- machineconfig/scripts/linux/url2md +1 -9
- machineconfig/scripts/python/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/croshell.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-313.pyc +0 -0
- machineconfig/scripts/python/cloud_mount.py +4 -2
- machineconfig/scripts/python/cloud_repo_sync.py +5 -2
- machineconfig/scripts/python/cloud_sync.py +4 -2
- machineconfig/scripts/python/croshell.py +5 -3
- machineconfig/scripts/python/devops.py +3 -2
- machineconfig/scripts/python/devops_devapps_install.py +1 -0
- machineconfig/scripts/python/fire_agents.py +6 -6
- machineconfig/scripts/python/fire_jobs.py +26 -72
- machineconfig/scripts/python/fire_jobs_args_helper.py +84 -0
- machineconfig/scripts/python/fire_jobs_layout_helper.py +66 -0
- machineconfig/scripts/python/helpers/helpers4.py +0 -1
- machineconfig/scripts/python/mount_nfs.py +12 -8
- machineconfig/scripts/python/mount_nw_drive.py +6 -6
- machineconfig/scripts/python/mount_ssh.py +4 -2
- machineconfig/scripts/python/start_slidev.py +4 -2
- machineconfig/scripts/python/start_terminals.py +4 -2
- machineconfig/scripts/python/wifi_conn.py +0 -1
- machineconfig/settings/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/settings/shells/ipy/profiles/default/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/settings/shells/ipy/profiles/default/startup/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/utils/code.py +5 -6
- machineconfig/utils/installer_utils/installer_abc.py +0 -1
- machineconfig/utils/options.py +7 -7
- machineconfig/utils/path.py +12 -12
- machineconfig/utils/path_reduced.py +6 -1
- machineconfig/utils/source_of_truth.py +2 -2
- machineconfig/utils/ssh.py +11 -1
- machineconfig/utils/upgrade_packages.py +12 -12
- {machineconfig-2.2.dist-info → machineconfig-2.4.dist-info}/METADATA +1 -1
- {machineconfig-2.2.dist-info → machineconfig-2.4.dist-info}/RECORD +90 -93
- machineconfig-2.4.dist-info/entry_points.txt +2 -0
- machineconfig/cluster/sessions_managers/archive/create_zellij_template.py +0 -60
- machineconfig/cluster/sessions_managers/archive/session_managers.py +0 -183
- machineconfig/cluster/sessions_managers/demo_rich_zellij.py +0 -0
- machineconfig/jobs/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/linux/archive/tmate_conn +0 -12
- machineconfig/scripts/linux/archive/tmate_start +0 -12
- machineconfig/scripts/linux/archive/transfer_wsl_win +0 -5
- machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_agents.cpython-313.pyc +0 -0
- /machineconfig/cluster/{cloud_manager.py → remote/cloud_manager.py} +0 -0
- /machineconfig/cluster/{data_transfer.py → remote/data_transfer.py} +0 -0
- /machineconfig/cluster/{distribute.py → remote/distribute.py} +0 -0
- /machineconfig/cluster/{file_manager.py → remote/file_manager.py} +0 -0
- /machineconfig/cluster/{job_params.py → remote/job_params.py} +0 -0
- /machineconfig/cluster/{loader_runner.py → remote/loader_runner.py} +0 -0
- /machineconfig/cluster/{remote_machine.py → remote/remote_machine.py} +0 -0
- /machineconfig/cluster/{script_execution.py → remote/script_execution.py} +0 -0
- /machineconfig/cluster/{script_notify_upon_completion.py → remote/script_notify_upon_completion.py} +0 -0
- /machineconfig/{cluster/sessions_managers/archive/__init__.py → scripts/python/fire_jobs_streamlit_helper.py} +0 -0
- {machineconfig-2.2.dist-info → machineconfig-2.4.dist-info}/WHEEL +0 -0
- {machineconfig-2.2.dist-info → machineconfig-2.4.dist-info}/top_level.txt +0 -0
machineconfig/__init__.py
CHANGED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version as _pkg_version
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import tomllib
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _get_version() -> str:
|
|
9
|
+
name: str = "machineconfig"
|
|
10
|
+
try:
|
|
11
|
+
return _pkg_version(name)
|
|
12
|
+
except PackageNotFoundError:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
root: Path = Path(__file__).resolve().parents[2]
|
|
16
|
+
pyproject: Path = root / "pyproject.toml"
|
|
17
|
+
if pyproject.is_file():
|
|
18
|
+
with pyproject.open("rb") as f:
|
|
19
|
+
data: dict[str, object] = tomllib.load(f)
|
|
20
|
+
project = data.get("project")
|
|
21
|
+
if isinstance(project, dict):
|
|
22
|
+
version = project.get("version")
|
|
23
|
+
if isinstance(version, str) and version:
|
|
24
|
+
return version
|
|
25
|
+
return "0.0.0"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
__version__: str = _get_version()
|
|
29
|
+
__all__: list[str] = ["__version__"]
|
|
30
|
+
|
|
@@ -84,7 +84,6 @@ def enhanced_zellij_session_start(session_name: str, layout_path: str) -> Dict[s
|
|
|
84
84
|
"""
|
|
85
85
|
console.print()
|
|
86
86
|
console.print(Panel.fit(f"🚀 Starting Zellij Session: [bold cyan]{session_name}[/bold cyan]", style="green", box=box.ROUNDED))
|
|
87
|
-
|
|
88
87
|
# Delete existing session first (suppress normal output)
|
|
89
88
|
delete_cmd = f"zellij delete-session --force {session_name}"
|
|
90
89
|
run_enhanced_command(
|
|
@@ -93,7 +92,6 @@ def enhanced_zellij_session_start(session_name: str, layout_path: str) -> Dict[s
|
|
|
93
92
|
show_progress=False,
|
|
94
93
|
timeout=5, # Quick timeout for cleanup
|
|
95
94
|
)
|
|
96
|
-
|
|
97
95
|
# Start new session (use -b for background to avoid hanging)
|
|
98
96
|
start_cmd = f"zellij --layout {layout_path} a -b {session_name}"
|
|
99
97
|
start_result = run_enhanced_command(
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Type definitions for the standardized layout configuration schema.
|
|
4
|
+
This module defines the data structures that match the layout.json schema.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import TypedDict, List
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TabConfig(TypedDict):
|
|
11
|
+
"""Configuration for a single tab in a layout."""
|
|
12
|
+
|
|
13
|
+
tabName: str
|
|
14
|
+
startDir: str
|
|
15
|
+
command: str
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class LayoutConfig(TypedDict):
|
|
19
|
+
"""Configuration for a complete layout with its tabs."""
|
|
20
|
+
|
|
21
|
+
layoutName: str
|
|
22
|
+
layoutTabs: List[TabConfig]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class LayoutsFile(TypedDict):
|
|
26
|
+
"""Complete layout file structure."""
|
|
27
|
+
|
|
28
|
+
version: str
|
|
29
|
+
layouts: List[LayoutConfig]
|
|
@@ -13,6 +13,8 @@ from typing import Dict, List, Optional, Any
|
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
import logging
|
|
15
15
|
|
|
16
|
+
from machineconfig.cluster.sessions_managers.layout_types import LayoutConfig, TabConfig
|
|
17
|
+
|
|
16
18
|
logging.basicConfig(level=logging.INFO)
|
|
17
19
|
logger = logging.getLogger(__name__)
|
|
18
20
|
TMP_LAYOUT_DIR = Path.home().joinpath("tmp_results", "session_manager", "wt", "layout_manager")
|
|
@@ -21,12 +23,12 @@ TMP_LAYOUT_DIR = Path.home().joinpath("tmp_results", "session_manager", "wt", "l
|
|
|
21
23
|
class WTLayoutGenerator:
|
|
22
24
|
def __init__(self):
|
|
23
25
|
self.session_name: Optional[str] = None
|
|
24
|
-
self.
|
|
25
|
-
self.script_path: Optional[str] = None # Store the full path to the script
|
|
26
|
+
self.layout_config: Optional[LayoutConfig] = None # Store the complete layout config
|
|
27
|
+
self.script_path: Optional[str] = None # Store the full path to the PowerShell script
|
|
26
28
|
|
|
27
29
|
@staticmethod
|
|
28
30
|
def _generate_random_suffix(length: int = 8) -> str:
|
|
29
|
-
"""Generate a random string suffix for unique script
|
|
31
|
+
"""Generate a random string suffix for unique PowerShell script names."""
|
|
30
32
|
return "".join(random.choices(string.ascii_lowercase + string.digits, k=length))
|
|
31
33
|
|
|
32
34
|
@staticmethod
|
|
@@ -51,8 +53,12 @@ class WTLayoutGenerator:
|
|
|
51
53
|
return text
|
|
52
54
|
|
|
53
55
|
@staticmethod
|
|
54
|
-
def _create_tab_command(
|
|
55
|
-
"""Create a Windows Terminal tab command string."""
|
|
56
|
+
def _create_tab_command(tab_config: TabConfig, is_first_tab: bool = False) -> str:
|
|
57
|
+
"""Create a Windows Terminal tab command string from tab config."""
|
|
58
|
+
tab_name = tab_config["tabName"]
|
|
59
|
+
cwd = tab_config["startDir"]
|
|
60
|
+
command = tab_config["command"]
|
|
61
|
+
|
|
56
62
|
# Convert paths to Windows format if needed
|
|
57
63
|
if cwd.startswith("~/"):
|
|
58
64
|
cwd = cwd.replace("~/", f"{Path.home()}/")
|
|
@@ -77,63 +83,55 @@ class WTLayoutGenerator:
|
|
|
77
83
|
return " ".join(tab_parts)
|
|
78
84
|
|
|
79
85
|
@staticmethod
|
|
80
|
-
def
|
|
81
|
-
"""Validate
|
|
82
|
-
if not
|
|
83
|
-
raise ValueError("
|
|
84
|
-
for
|
|
85
|
-
if not
|
|
86
|
-
raise ValueError(f"Invalid tab name: {
|
|
87
|
-
if not command.strip():
|
|
88
|
-
raise ValueError(f"Invalid command for tab '{
|
|
89
|
-
if not
|
|
90
|
-
raise ValueError(f"Invalid
|
|
91
|
-
|
|
92
|
-
def create_wt_layout(self,
|
|
93
|
-
WTLayoutGenerator.
|
|
94
|
-
logger.info(f"Creating Windows Terminal layout with {len(
|
|
95
|
-
|
|
96
|
-
# Store session name and
|
|
97
|
-
self.session_name =
|
|
98
|
-
self.
|
|
86
|
+
def _validate_layout_config(layout_config: LayoutConfig) -> None:
|
|
87
|
+
"""Validate layout configuration format and content."""
|
|
88
|
+
if not layout_config["layoutTabs"]:
|
|
89
|
+
raise ValueError("Layout must contain at least one tab")
|
|
90
|
+
for tab in layout_config["layoutTabs"]:
|
|
91
|
+
if not tab["tabName"].strip():
|
|
92
|
+
raise ValueError(f"Invalid tab name: {tab['tabName']}")
|
|
93
|
+
if not tab["command"].strip():
|
|
94
|
+
raise ValueError(f"Invalid command for tab '{tab['tabName']}': {tab['command']}")
|
|
95
|
+
if not tab["startDir"].strip():
|
|
96
|
+
raise ValueError(f"Invalid startDir for tab '{tab['tabName']}': {tab['startDir']}")
|
|
97
|
+
|
|
98
|
+
def create_wt_layout(self, layout_config: LayoutConfig, output_dir: Optional[str] = None) -> str:
|
|
99
|
+
WTLayoutGenerator._validate_layout_config(layout_config)
|
|
100
|
+
logger.info(f"Creating Windows Terminal layout '{layout_config['layoutName']}' with {len(layout_config['layoutTabs'])} tabs")
|
|
101
|
+
|
|
102
|
+
# Store session name and layout config for status checking
|
|
103
|
+
self.session_name = layout_config["layoutName"]
|
|
104
|
+
self.layout_config = layout_config.copy()
|
|
99
105
|
|
|
100
106
|
# Generate Windows Terminal command
|
|
101
|
-
wt_command = self._generate_wt_command_string(
|
|
107
|
+
wt_command = self._generate_wt_command_string(layout_config, self.session_name)
|
|
102
108
|
|
|
103
109
|
try:
|
|
104
110
|
random_suffix = WTLayoutGenerator._generate_random_suffix()
|
|
105
111
|
if output_dir:
|
|
106
112
|
output_path = Path(output_dir)
|
|
107
113
|
output_path.mkdir(parents=True, exist_ok=True)
|
|
108
|
-
script_file = output_path / f"wt_layout_{random_suffix}.
|
|
114
|
+
script_file = output_path / f"wt_layout_{random_suffix}.ps1"
|
|
109
115
|
else:
|
|
110
116
|
# Use the predefined TMP_LAYOUT_DIR for temporary files
|
|
111
117
|
TMP_LAYOUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
112
|
-
script_file = TMP_LAYOUT_DIR / f"wt_layout_{self.session_name}_{random_suffix}.
|
|
113
|
-
|
|
114
|
-
# Create batch script
|
|
115
|
-
text = f"""@echo off
|
|
116
|
-
REM Windows Terminal layout for {self.session_name}
|
|
117
|
-
{wt_command}
|
|
118
|
-
"""
|
|
119
|
-
script_file.write_text(text, encoding="utf-8")
|
|
118
|
+
script_file = TMP_LAYOUT_DIR / f"wt_layout_{self.session_name}_{random_suffix}.ps1"
|
|
120
119
|
|
|
121
|
-
#
|
|
122
|
-
ps1_file = script_file.with_suffix(".ps1")
|
|
120
|
+
# Create PowerShell script
|
|
123
121
|
text = f"""# Windows Terminal layout for {self.session_name}
|
|
124
122
|
# Generated with random suffix: {random_suffix}
|
|
125
123
|
{wt_command}
|
|
126
124
|
"""
|
|
127
|
-
|
|
125
|
+
script_file.write_text(text, encoding="utf-8")
|
|
128
126
|
|
|
129
127
|
self.script_path = str(script_file.absolute())
|
|
130
|
-
logger.info(f"Windows Terminal script
|
|
128
|
+
logger.info(f"Windows Terminal PowerShell script created: {self.script_path}")
|
|
131
129
|
return self.script_path
|
|
132
130
|
except OSError as e:
|
|
133
|
-
logger.error(f"Failed to create script
|
|
131
|
+
logger.error(f"Failed to create PowerShell script: {e}")
|
|
134
132
|
raise
|
|
135
133
|
|
|
136
|
-
def _generate_wt_command_string(self,
|
|
134
|
+
def _generate_wt_command_string(self, layout_config: LayoutConfig, window_name: str) -> str:
|
|
137
135
|
"""Generate complete Windows Terminal command string."""
|
|
138
136
|
# Start building the wt command
|
|
139
137
|
wt_parts = ["wt"]
|
|
@@ -143,9 +141,9 @@ REM Windows Terminal layout for {self.session_name}
|
|
|
143
141
|
|
|
144
142
|
# Add tabs
|
|
145
143
|
tab_commands = []
|
|
146
|
-
for i,
|
|
144
|
+
for i, tab in enumerate(layout_config["layoutTabs"]):
|
|
147
145
|
is_first = i == 0
|
|
148
|
-
tab_cmd = self._create_tab_command(
|
|
146
|
+
tab_cmd = self._create_tab_command(tab, is_first)
|
|
149
147
|
tab_commands.append(tab_cmd)
|
|
150
148
|
|
|
151
149
|
# Join all parts with semicolons (Windows Terminal command separator)
|
|
@@ -161,19 +159,20 @@ REM Windows Terminal layout for {self.session_name}
|
|
|
161
159
|
|
|
162
160
|
return " ".join(wt_parts)
|
|
163
161
|
|
|
164
|
-
def get_wt_layout_preview(self,
|
|
162
|
+
def get_wt_layout_preview(self, layout_config: LayoutConfig) -> str:
|
|
165
163
|
"""Generate preview of the Windows Terminal command that would be created."""
|
|
166
|
-
WTLayoutGenerator.
|
|
167
|
-
return self._generate_wt_command_string(
|
|
164
|
+
WTLayoutGenerator._validate_layout_config(layout_config)
|
|
165
|
+
return self._generate_wt_command_string(layout_config, "preview")
|
|
168
166
|
|
|
169
167
|
def check_all_commands_status(self) -> Dict[str, Dict[str, Any]]:
|
|
170
|
-
if not self.
|
|
171
|
-
logger.warning("No
|
|
168
|
+
if not self.layout_config:
|
|
169
|
+
logger.warning("No layout config tracked. Make sure to create a layout first.")
|
|
172
170
|
return {}
|
|
173
171
|
|
|
174
172
|
status_report = {}
|
|
175
|
-
for
|
|
176
|
-
|
|
173
|
+
for tab in self.layout_config["layoutTabs"]:
|
|
174
|
+
tab_name = tab["tabName"]
|
|
175
|
+
status_report[tab_name] = WTLayoutGenerator.check_command_status(tab_name, self.layout_config)
|
|
177
176
|
|
|
178
177
|
return status_report
|
|
179
178
|
|
|
@@ -218,12 +217,19 @@ REM Windows Terminal layout for {self.session_name}
|
|
|
218
217
|
return {"wt_running": False, "error": str(e), "session_name": session_name}
|
|
219
218
|
|
|
220
219
|
@staticmethod
|
|
221
|
-
def check_command_status(tab_name: str,
|
|
220
|
+
def check_command_status(tab_name: str, layout_config: LayoutConfig) -> Dict[str, Any]:
|
|
222
221
|
"""Check if a command is running by looking for processes."""
|
|
223
|
-
|
|
224
|
-
|
|
222
|
+
# Find the tab with the given name
|
|
223
|
+
tab_config = None
|
|
224
|
+
for tab in layout_config["layoutTabs"]:
|
|
225
|
+
if tab["tabName"] == tab_name:
|
|
226
|
+
tab_config = tab
|
|
227
|
+
break
|
|
228
|
+
|
|
229
|
+
if tab_config is None:
|
|
230
|
+
return {"status": "unknown", "error": f"Tab '{tab_name}' not found in layout config", "running": False, "pid": None, "command": None}
|
|
225
231
|
|
|
226
|
-
|
|
232
|
+
command = tab_config["command"]
|
|
227
233
|
|
|
228
234
|
try:
|
|
229
235
|
# Create PowerShell script to check for processes
|
|
@@ -361,22 +367,22 @@ Get-Process | ForEach-Object {{
|
|
|
361
367
|
print("=" * 80)
|
|
362
368
|
|
|
363
369
|
|
|
364
|
-
def create_wt_layout(
|
|
370
|
+
def create_wt_layout(layout_config: LayoutConfig, output_dir: Optional[str] = None) -> str:
|
|
365
371
|
generator = WTLayoutGenerator()
|
|
366
|
-
return generator.create_wt_layout(
|
|
372
|
+
return generator.create_wt_layout(layout_config, output_dir)
|
|
367
373
|
|
|
368
374
|
|
|
369
|
-
def run_wt_layout(
|
|
375
|
+
def run_wt_layout(layout_config: LayoutConfig) -> str:
|
|
370
376
|
"""Create and run a Windows Terminal layout."""
|
|
371
377
|
generator = WTLayoutGenerator()
|
|
372
|
-
script_path = generator.create_wt_layout(
|
|
378
|
+
script_path = generator.create_wt_layout(layout_config)
|
|
373
379
|
|
|
374
380
|
# Execute the script
|
|
375
381
|
cmd = f'powershell -ExecutionPolicy Bypass -File "{script_path}"'
|
|
376
382
|
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
|
377
383
|
|
|
378
384
|
if result.returncode == 0:
|
|
379
|
-
print(f"Windows Terminal layout is running @ {
|
|
385
|
+
print(f"Windows Terminal layout is running @ {layout_config['layoutName']}")
|
|
380
386
|
return script_path
|
|
381
387
|
else:
|
|
382
388
|
logger.error(f"Failed to run Windows Terminal layout: {result.stderr}")
|
|
@@ -394,17 +400,17 @@ wt new-tab --title "{tab_name}" {cwd_part} "{command}"
|
|
|
394
400
|
|
|
395
401
|
|
|
396
402
|
if __name__ == "__main__":
|
|
397
|
-
# Example usage
|
|
398
|
-
|
|
403
|
+
# Example usage with new schema
|
|
404
|
+
sample_layout: LayoutConfig = {"layoutName": "TestLayout", "layoutTabs": [{"tabName": "Frontend", "startDir": "~/code", "command": "btm"}, {"tabName": "Monitor", "startDir": "~", "command": "lf"}]}
|
|
399
405
|
|
|
400
406
|
try:
|
|
401
407
|
# Create layout using the generator
|
|
402
408
|
generator = WTLayoutGenerator()
|
|
403
|
-
script_path = generator.create_wt_layout(
|
|
409
|
+
script_path = generator.create_wt_layout(sample_layout)
|
|
404
410
|
print(f"✅ Windows Terminal layout created: {script_path}")
|
|
405
411
|
|
|
406
412
|
# Show preview
|
|
407
|
-
preview = generator.get_wt_layout_preview(
|
|
413
|
+
preview = generator.get_wt_layout_preview(sample_layout)
|
|
408
414
|
print(f"\n📋 Command Preview:\n{preview}")
|
|
409
415
|
|
|
410
416
|
# Check status (won't find anything since we haven't run it)
|
|
@@ -8,6 +8,7 @@ from pathlib import Path
|
|
|
8
8
|
from typing import Optional, Dict, List, Any
|
|
9
9
|
from machineconfig.utils.utils5 import Scheduler
|
|
10
10
|
from machineconfig.cluster.sessions_managers.wt_local import WTLayoutGenerator
|
|
11
|
+
from machineconfig.cluster.sessions_managers.layout_types import LayoutConfig
|
|
11
12
|
|
|
12
13
|
logging.basicConfig(level=logging.INFO)
|
|
13
14
|
logger = logging.getLogger(__name__)
|
|
@@ -18,24 +19,23 @@ TMP_SERIALIZATION_DIR = Path.home().joinpath("tmp_results", "session_manager", "
|
|
|
18
19
|
class WTLocalManager:
|
|
19
20
|
"""Manages multiple local Windows Terminal sessions and monitors their tabs and processes."""
|
|
20
21
|
|
|
21
|
-
def __init__(self,
|
|
22
|
+
def __init__(self, session_layouts: list[LayoutConfig], session_name_prefix: str = "LocalWTMgr"):
|
|
22
23
|
"""
|
|
23
24
|
Initialize the local Windows Terminal manager.
|
|
24
25
|
|
|
25
26
|
Args:
|
|
26
|
-
|
|
27
|
-
Format: {session_name:
|
|
27
|
+
session_layouts: Dict mapping session names to their layout configs
|
|
28
|
+
Format: {session_name: LayoutConfig, ...}
|
|
28
29
|
session_name_prefix: Prefix for session names
|
|
29
30
|
"""
|
|
30
31
|
self.session_name_prefix = session_name_prefix
|
|
31
|
-
self.
|
|
32
|
+
self.session_layouts = session_layouts # Store the original config
|
|
32
33
|
self.managers: List[WTLayoutGenerator] = []
|
|
33
34
|
|
|
34
35
|
# Create a WTLayoutGenerator for each session
|
|
35
|
-
for
|
|
36
|
+
for layout_config in session_layouts:
|
|
36
37
|
manager = WTLayoutGenerator()
|
|
37
|
-
|
|
38
|
-
manager.create_wt_layout(tab_config=tab_config, session_name=full_session_name)
|
|
38
|
+
manager.create_wt_layout(layout_config=layout_config)
|
|
39
39
|
self.managers.append(manager)
|
|
40
40
|
|
|
41
41
|
logger.info(f"Initialized WTLocalManager with {len(self.managers)} sessions")
|
|
@@ -288,12 +288,12 @@ class WTLocalManager:
|
|
|
288
288
|
session_dir.mkdir(parents=True, exist_ok=True)
|
|
289
289
|
|
|
290
290
|
# Save the session2wt_tabs configuration
|
|
291
|
-
config_file = session_dir / "
|
|
292
|
-
text = json.dumps(self.
|
|
291
|
+
config_file = session_dir / "session_layouts.json"
|
|
292
|
+
text = json.dumps(self.session_layouts, indent=2, ensure_ascii=False)
|
|
293
293
|
config_file.write_text(text, encoding="utf-8")
|
|
294
294
|
|
|
295
295
|
# Save metadata
|
|
296
|
-
metadata = {"session_name_prefix": self.session_name_prefix, "created_at": str(datetime.now()), "num_managers": len(self.managers), "sessions":
|
|
296
|
+
metadata = {"session_name_prefix": self.session_name_prefix, "created_at": str(datetime.now()), "num_managers": len(self.managers), "sessions": [item["layoutName"] for item in self.session_layouts], "manager_type": "WTLocalManager"}
|
|
297
297
|
metadata_file = session_dir / "metadata.json"
|
|
298
298
|
text = json.dumps(metadata, indent=2, ensure_ascii=False)
|
|
299
299
|
metadata_file.write_text(text, encoding="utf-8")
|
|
@@ -303,7 +303,7 @@ class WTLocalManager:
|
|
|
303
303
|
managers_dir.mkdir(exist_ok=True)
|
|
304
304
|
|
|
305
305
|
for i, manager in enumerate(self.managers):
|
|
306
|
-
manager_data = {"session_name": manager.session_name, "
|
|
306
|
+
manager_data = {"session_name": manager.session_name, "layout_config": manager.layout_config, "script_path": manager.script_path}
|
|
307
307
|
manager_file = managers_dir / f"manager_{i}_{manager.session_name}.json"
|
|
308
308
|
text = json.dumps(manager_data, indent=2, ensure_ascii=False)
|
|
309
309
|
manager_file.write_text(text, encoding="utf-8")
|
|
@@ -320,12 +320,12 @@ class WTLocalManager:
|
|
|
320
320
|
raise FileNotFoundError(f"Session directory not found: {session_dir}")
|
|
321
321
|
|
|
322
322
|
# Load configuration
|
|
323
|
-
config_file = session_dir / "
|
|
323
|
+
config_file = session_dir / "session_layouts.json"
|
|
324
324
|
if not config_file.exists():
|
|
325
325
|
raise FileNotFoundError(f"Configuration file not found: {config_file}")
|
|
326
326
|
|
|
327
327
|
with open(config_file, "r", encoding="utf-8") as f:
|
|
328
|
-
|
|
328
|
+
session_layouts = json.load(f)
|
|
329
329
|
|
|
330
330
|
# Load metadata
|
|
331
331
|
metadata_file = session_dir / "metadata.json"
|
|
@@ -336,7 +336,7 @@ class WTLocalManager:
|
|
|
336
336
|
session_name_prefix = metadata.get("session_name_prefix", "LocalWTMgr")
|
|
337
337
|
|
|
338
338
|
# Create new instance
|
|
339
|
-
instance = cls(
|
|
339
|
+
instance = cls(session_layouts=session_layouts, session_name_prefix=session_name_prefix)
|
|
340
340
|
|
|
341
341
|
# Load saved manager states
|
|
342
342
|
managers_dir = session_dir / "managers"
|
|
@@ -352,7 +352,7 @@ class WTLocalManager:
|
|
|
352
352
|
# Recreate the manager
|
|
353
353
|
manager = WTLayoutGenerator()
|
|
354
354
|
manager.session_name = manager_data["session_name"]
|
|
355
|
-
manager.
|
|
355
|
+
manager.layout_config = manager_data["layout_config"]
|
|
356
356
|
manager.script_path = manager_data["script_path"]
|
|
357
357
|
|
|
358
358
|
instance.managers.append(manager)
|
|
@@ -422,7 +422,15 @@ class WTLocalManager:
|
|
|
422
422
|
if session_name in window_title or not window_title:
|
|
423
423
|
session_windows.append(proc)
|
|
424
424
|
|
|
425
|
-
active_sessions.append(
|
|
425
|
+
active_sessions.append(
|
|
426
|
+
{
|
|
427
|
+
"session_name": session_name,
|
|
428
|
+
"is_active": len(session_windows) > 0,
|
|
429
|
+
"tab_count": len(manager.layout_config["layoutTabs"]) if manager.layout_config else 0,
|
|
430
|
+
"tabs": [tab["tabName"] for tab in manager.layout_config["layoutTabs"]] if manager.layout_config else [],
|
|
431
|
+
"windows": session_windows,
|
|
432
|
+
}
|
|
433
|
+
)
|
|
426
434
|
|
|
427
435
|
except Exception as e:
|
|
428
436
|
logger.error(f"Error listing active sessions: {e}")
|
|
@@ -451,12 +459,33 @@ class WTLocalManager:
|
|
|
451
459
|
|
|
452
460
|
|
|
453
461
|
if __name__ == "__main__":
|
|
454
|
-
# Example usage
|
|
455
|
-
sample_sessions =
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
462
|
+
# Example usage with new schema
|
|
463
|
+
sample_sessions: list[LayoutConfig] = [
|
|
464
|
+
{
|
|
465
|
+
"layoutName": "DevelopmentEnv",
|
|
466
|
+
"layoutTabs": [
|
|
467
|
+
{"tabName": "🚀Frontend", "startDir": "~/code/myapp/frontend", "command": "npm run dev"},
|
|
468
|
+
{"tabName": "⚙️Backend", "startDir": "~/code/myapp/backend", "command": "python manage.py runserver"},
|
|
469
|
+
{"tabName": "📊Monitor", "startDir": "~", "command": "Get-Process | Sort-Object CPU -Descending | Select-Object -First 10"},
|
|
470
|
+
],
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
"layoutName": "TestingEnv",
|
|
474
|
+
"layoutTabs": [
|
|
475
|
+
{"tabName": "🧪Tests", "startDir": "~/code/myapp", "command": "pytest --watch"},
|
|
476
|
+
{"tabName": "🔍Coverage", "startDir": "~/code/myapp", "command": "python -m coverage run --source=. -m pytest"},
|
|
477
|
+
{"tabName": "📝Logs", "startDir": "~/logs", "command": "Get-Content app.log -Wait"},
|
|
478
|
+
],
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
"layoutName": "DeploymentEnv",
|
|
482
|
+
"layoutTabs": [
|
|
483
|
+
{"tabName": "🐳Docker", "startDir": "~/code/myapp", "command": "docker-compose up"},
|
|
484
|
+
{"tabName": "☸️K8s", "startDir": "~/k8s", "command": "kubectl get pods --watch"},
|
|
485
|
+
{"tabName": "📈Metrics", "startDir": "~", "command": 'Get-Counter "\\Processor(_Total)\\% Processor Time" -SampleInterval 2 -MaxSamples 30'},
|
|
486
|
+
],
|
|
487
|
+
},
|
|
488
|
+
]
|
|
460
489
|
|
|
461
490
|
try:
|
|
462
491
|
# Create the local manager
|