machineconfig 8.51__py3-none-any.whl → 8.61__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.
- machineconfig/jobs/installer/python_scripts/sysabc.py +13 -34
- machineconfig/profile/mapper_dotfiles.toml +3 -3
- machineconfig/scripts/python/devops.py +1 -1
- machineconfig/scripts/python/devops_navigator.py +1 -1
- machineconfig/scripts/python/helper_env/path_manager_tui.py +1 -1
- machineconfig/scripts/python/helpers/helper_env/env_manager_tui.py +1 -1
- machineconfig/scripts/python/helpers/helper_env/path_manager_tui.py +1 -1
- machineconfig/scripts/python/helpers/helpers_croshell/croshell_impl.py +8 -4
- machineconfig/scripts/python/helpers/helpers_devops/cli_config.py +33 -1
- machineconfig/scripts/python/helpers/helpers_devops/cli_config_mount.py +77 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_data.py +4 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_nw.py +90 -6
- machineconfig/scripts/python/helpers/helpers_devops/cli_repos.py +3 -3
- machineconfig/scripts/python/helpers/helpers_devops/cli_self.py +41 -15
- machineconfig/scripts/python/helpers/helpers_devops/cli_share_temp.py +69 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_ssh.py +4 -4
- machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/__init__.py +0 -0
- machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/commands.py +25 -0
- machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/device_entry.py +17 -0
- machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/devices.py +17 -0
- machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/linux.py +103 -0
- machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/macos.py +100 -0
- machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/selection.py +47 -0
- machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/utils.py +28 -0
- machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/windows.py +91 -0
- machineconfig/scripts/python/helpers/helpers_msearch/scripts_windows/fzfg.ps1 +1 -6
- machineconfig/scripts/python/helpers/helpers_network/ssh/__init__.py +0 -0
- machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_add_key_windows.py +23 -0
- machineconfig/scripts/python/helpers/helpers_network/{ssh_add_ssh_key.py → ssh/ssh_add_ssh_key.py} +21 -27
- machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_cloud_init.py +33 -0
- machineconfig/scripts/python/helpers/helpers_network/{ssh_debug_linux.py → ssh/ssh_debug_linux.py} +70 -51
- machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_debug_linux_utils.py +35 -0
- machineconfig/scripts/python/helpers/helpers_network/{ssh_debug_windows.py → ssh/ssh_debug_windows.py} +12 -42
- machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_debug_windows_utils.py +34 -0
- machineconfig/scripts/python/helpers/helpers_repos/cloud_repo_sync.py +2 -3
- machineconfig/scripts/python/helpers/{helpers_terminal/terminal_impl.py → helpers_sessions/attach_impl.py} +16 -25
- machineconfig/scripts/python/helpers/helpers_sessions/sessions_impl.py +57 -129
- machineconfig/scripts/python/helpers/helpers_sessions/utils.py +69 -0
- machineconfig/scripts/python/mcfg_entry.py +0 -7
- machineconfig/scripts/python/sessions.py +95 -14
- machineconfig/scripts/python/utils.py +3 -2
- machineconfig/settings/shells/bash/init.sh +0 -7
- machineconfig/settings/shells/pwsh/init.ps1 +2 -4
- machineconfig/settings/shells/wezterm/wezterm.lua +1 -0
- machineconfig/settings/shells/wt/settings.json +13 -19
- machineconfig/settings/shells/zsh/init.sh +0 -1
- machineconfig/settings/zellij/__init__.py +0 -0
- machineconfig/settings/zellij/config.kdl +0 -295
- machineconfig/settings/zellij/layouts/__init__.py +0 -0
- machineconfig/settings/zellij/layouts/st.kdl +0 -1
- machineconfig/settings/zellij/layouts/st2.kdl +6 -2
- machineconfig/setup_linux/web_shortcuts/interactive.sh +10 -10
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +10 -10
- machineconfig/utils/installer_utils/installer_cli.py +6 -2
- machineconfig/utils/installer_utils/installer_helper.py +50 -34
- machineconfig/utils/installer_utils/installer_locator_utils.py +3 -13
- machineconfig/utils/options_utils/tv_options.py +1 -1
- machineconfig/utils/procs.py +35 -27
- machineconfig/utils/schemas/layouts/layout_types.py +10 -0
- machineconfig/utils/source_of_truth.py +1 -0
- machineconfig/utils/ssh_utils/abc.py +1 -1
- {machineconfig-8.51.dist-info → machineconfig-8.61.dist-info}/METADATA +2 -3
- {machineconfig-8.51.dist-info → machineconfig-8.61.dist-info}/RECORD +68 -72
- {machineconfig-8.51.dist-info → machineconfig-8.61.dist-info}/entry_points.txt +0 -1
- machineconfig/jobs/scripts/bash_scripts/android.sh +0 -2
- machineconfig/jobs/scripts/bash_scripts/mount_drive +0 -128
- machineconfig/jobs/scripts/bash_scripts/mount_nfs +0 -49
- machineconfig/jobs/scripts/bash_scripts/mount_nw_drive +0 -61
- machineconfig/jobs/scripts/bash_scripts/mount_smb +0 -3
- machineconfig/jobs/scripts/bash_scripts/share_cloud.sh +0 -64
- machineconfig/jobs/scripts/bash_scripts/share_nfs +0 -49
- machineconfig/jobs/scripts/bash_scripts/start_docker +0 -23
- machineconfig/jobs/scripts/powershell_scripts/Restore-ThunderbirdProfile.ps1 +0 -92
- machineconfig/jobs/scripts/powershell_scripts/docker.ps1 +0 -7
- machineconfig/jobs/scripts/powershell_scripts/mount_nfs.ps1 +0 -42
- machineconfig/jobs/scripts/powershell_scripts/mount_nw.ps1 +0 -9
- machineconfig/jobs/scripts/powershell_scripts/mount_smb.ps1 +0 -2
- machineconfig/jobs/scripts/powershell_scripts/mount_ssh.ps1 +0 -13
- machineconfig/jobs/scripts/powershell_scripts/obs.ps1 +0 -4
- machineconfig/jobs/scripts/powershell_scripts/power_options.ps1 +0 -7
- machineconfig/jobs/scripts/powershell_scripts/share_cloud.cmd +0 -34
- machineconfig/jobs/scripts/powershell_scripts/share_smb.ps1 +0 -16
- machineconfig/scripts/python/helpers/helpers_network/mount_nfs.py +0 -85
- machineconfig/scripts/python/helpers/helpers_network/mount_nw_drive.py +0 -48
- machineconfig/scripts/python/helpers/helpers_network/mount_ssh.py +0 -64
- machineconfig/scripts/python/terminal.py +0 -58
- machineconfig/settings/zellij/config.orig.kdl +0 -295
- /machineconfig/{scripts/python/helpers/helpers_terminal → cluster/sessions_managers/wt_utils/examples}/__init__.py +0 -0
- /machineconfig/scripts/python/helpers/helpers_network/{ssh_add_identity.py → ssh/ssh_add_identity.py} +0 -0
- {machineconfig-8.51.dist-info → machineconfig-8.61.dist-info}/WHEEL +0 -0
- {machineconfig-8.51.dist-info → machineconfig-8.61.dist-info}/top_level.txt +0 -0
|
@@ -1,63 +1,37 @@
|
|
|
1
1
|
"""Pure Python implementations for sessions commands - no typer dependencies."""
|
|
2
2
|
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Literal
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
def
|
|
8
|
-
layout_path: str,
|
|
9
|
-
max_thresh: int,
|
|
10
|
-
thresh_type: Literal["number", "n", "weight", "w"],
|
|
11
|
-
breaking_method: Literal["moreLayouts", "ml", "combineTabs", "ct"],
|
|
12
|
-
output_path: Optional[str],
|
|
13
|
-
) -> None:
|
|
14
|
-
"""Adjust layout file to limit max tabs per layout, etc."""
|
|
15
|
-
thresh_type_resolved: dict[str, Literal["number", "weight"]] = {"number": "number", "n": "number", "weight": "weight", "w": "weight"}
|
|
16
|
-
breaking_method_resolved: dict[str, Literal["moreLayouts", "combineTabs"]] = {"moreLayouts": "moreLayouts", "ml": "moreLayouts", "combineTabs": "combineTabs", "ct": "combineTabs"}
|
|
17
|
-
|
|
18
|
-
layout_path_obj = Path(layout_path).expanduser().absolute()
|
|
19
|
-
|
|
20
|
-
from machineconfig.utils.schemas.layouts.layout_types import LayoutsFile
|
|
21
|
-
import json
|
|
22
|
-
layoutfile: LayoutsFile = json.loads(layout_path_obj.read_text())
|
|
23
|
-
layout_configs = layoutfile["layouts"]
|
|
24
|
-
from machineconfig.cluster.sessions_managers.utils.load_balancer import limit_tab_num
|
|
25
|
-
new_layouts = limit_tab_num(layout_configs=layout_configs, max_thresh=max_thresh, threshold_type=thresh_type_resolved[thresh_type], breaking_method=breaking_method_resolved[breaking_method])
|
|
26
|
-
layoutfile["layouts"] = new_layouts
|
|
27
|
-
target_file = Path(output_path) if output_path is not None else layout_path_obj.parent / f"{layout_path_obj.stem}_adjusted_{max_thresh}_{thresh_type}_{breaking_method}.json"
|
|
28
|
-
target_file.parent.mkdir(parents=True, exist_ok=True)
|
|
29
|
-
target_file.write_text(data=json.dumps(layoutfile, indent=4), encoding="utf-8")
|
|
30
|
-
print(f"Adjusted layout saved to {target_file}")
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def select_layout(layouts_json_file: str, selected_layouts_names: Optional[list[str]], select_interactively: bool, subsitute_home: bool) -> list["LayoutConfig"]: # type: ignore[name-defined]
|
|
7
|
+
def select_layout(layouts_json_file: str, selected_layouts_names: list[str], select_interactively: bool) -> list["LayoutConfig"]:
|
|
34
8
|
"""Select layout(s) from a layout file."""
|
|
35
9
|
import json
|
|
36
|
-
from machineconfig.utils.schemas.layouts.layout_types import LayoutsFile
|
|
10
|
+
from machineconfig.utils.schemas.layouts.layout_types import LayoutsFile
|
|
37
11
|
json_str = Path(layouts_json_file).read_text(encoding="utf-8")
|
|
38
|
-
if subsitute_home:
|
|
39
|
-
json_str = json_str.replace("~", str(Path.home())).replace("$HOME", str(Path.home()))
|
|
40
|
-
json_str = json_str.replace("""Command": "f """, """Command": "~/.config/machineconfig/scripts/wrap_mcfg fire """)
|
|
41
|
-
json_str = json_str.replace("""Command": "s """, """Command": "~/.config/machineconfig/scripts/wrap_mcfg sessions """)
|
|
42
|
-
|
|
43
12
|
try:
|
|
44
|
-
# src/machineconfig/utils/io.py
|
|
45
13
|
layout_file: LayoutsFile = json.loads(json_str)
|
|
46
14
|
except Exception:
|
|
47
15
|
print(f"Failed to parse the json file {layouts_json_file}, trying to clean the comments and giving it another shot ... ")
|
|
48
16
|
from machineconfig.utils.io import remove_c_style_comments
|
|
49
17
|
json_str = remove_c_style_comments(json_str)
|
|
50
|
-
# print(json_str)
|
|
51
18
|
layout_file: LayoutsFile = json.loads(json_str)
|
|
52
|
-
|
|
53
19
|
if len(layout_file["layouts"]) == 0:
|
|
54
20
|
raise ValueError(f"No layouts found in {layouts_json_file}")
|
|
55
|
-
if selected_layouts_names
|
|
21
|
+
if len(selected_layouts_names) == 0:
|
|
56
22
|
if not select_interactively:
|
|
57
23
|
return layout_file["layouts"]
|
|
58
|
-
options = [layout["layoutName"] for layout in layout_file["layouts"]]
|
|
59
|
-
from machineconfig.utils.options import choose_from_options
|
|
60
|
-
selected_layouts_names = choose_from_options(multi=True, options=options, prompt="Choose a layout configuration:", tv=True, msg="Choose one option")
|
|
24
|
+
# options = [layout["layoutName"] for layout in layout_file["layouts"]]
|
|
25
|
+
# from machineconfig.utils.options import choose_from_options
|
|
26
|
+
# selected_layouts_names = choose_from_options(multi=True, options=options, prompt="Choose a layout configuration:", tv=True, msg="Choose one option")
|
|
27
|
+
from machineconfig.utils.options_utils.tv_options import choose_from_dict_with_preview
|
|
28
|
+
selected_layouts_names = choose_from_dict_with_preview(
|
|
29
|
+
{layout["layoutName"]: json.dumps(layout, indent=4) for layout in layout_file["layouts"]},
|
|
30
|
+
extension="json",
|
|
31
|
+
multi=True,
|
|
32
|
+
preview_size_percent=40,
|
|
33
|
+
)
|
|
34
|
+
|
|
61
35
|
print(f"Selected layout(s): {selected_layouts_names}")
|
|
62
36
|
layouts_chosen: list[LayoutConfig] = []
|
|
63
37
|
for name in selected_layouts_names:
|
|
@@ -70,7 +44,6 @@ def select_layout(layouts_json_file: str, selected_layouts_names: Optional[list[
|
|
|
70
44
|
layouts_chosen.append(layout_chosen)
|
|
71
45
|
return layouts_chosen
|
|
72
46
|
|
|
73
|
-
|
|
74
47
|
def find_layout_file(layout_path: str) -> str:
|
|
75
48
|
"""Find layout file from a path."""
|
|
76
49
|
from machineconfig.utils.path_helper import search_for_files_of_interest, match_file_name, sanitize_path
|
|
@@ -90,97 +63,52 @@ def find_layout_file(layout_path: str) -> str:
|
|
|
90
63
|
|
|
91
64
|
|
|
92
65
|
def run_layouts(
|
|
93
|
-
layout_path: Optional[str],
|
|
94
|
-
max_tabs: int,
|
|
95
|
-
max_layouts: int,
|
|
96
66
|
sleep_inbetween: float,
|
|
97
67
|
monitor: bool,
|
|
98
|
-
|
|
68
|
+
sequential: bool,
|
|
99
69
|
kill_upon_completion: bool,
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
subsitute_home: bool,
|
|
70
|
+
backend: Literal["zellij", "windows-terminal"],
|
|
71
|
+
layouts_selected: list["LayoutConfig"],
|
|
103
72
|
) -> None:
|
|
104
73
|
"""Launch terminal sessions based on a layout configuration file."""
|
|
105
|
-
if layout_path is None:
|
|
106
|
-
raise ValueError("layout_path is required")
|
|
107
|
-
|
|
108
|
-
layout_path_resolved = find_layout_file(layout_path=layout_path)
|
|
109
|
-
layouts_selected = select_layout(layouts_json_file=layout_path_resolved, selected_layouts_names=choose.split(",") if choose else None, select_interactively=choose_interactively, subsitute_home=subsitute_home)
|
|
110
|
-
|
|
111
|
-
if parallel and len(layouts_selected) > max_layouts:
|
|
112
|
-
raise ValueError(f"Number of layouts {len(layouts_selected)} exceeds the maximum allowed {max_layouts}. Please adjust your layout file.")
|
|
113
|
-
for a_layout in layouts_selected:
|
|
114
|
-
if len(a_layout["layoutTabs"]) > max_tabs:
|
|
115
|
-
raise ValueError(f"Layout '{a_layout.get('layoutName', 'Unnamed')}' has {len(a_layout['layoutTabs'])} tabs which exceeds the max of {max_tabs}.")
|
|
116
|
-
|
|
117
74
|
import time
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
75
|
+
match backend:
|
|
76
|
+
case "zellij":
|
|
77
|
+
from machineconfig.cluster.sessions_managers.zellij_local_manager import ZellijLocalManager
|
|
78
|
+
if sequential:
|
|
79
|
+
iterable: list[list[LayoutConfig]] = [[item] for item in layouts_selected]
|
|
80
|
+
else:
|
|
81
|
+
iterable = [layouts_selected]
|
|
82
|
+
for i, a_layouts in enumerate(iterable):
|
|
83
|
+
manager = ZellijLocalManager(session_layouts=a_layouts)
|
|
84
|
+
manager.start_all_sessions(poll_interval=2, poll_seconds=2)
|
|
85
|
+
if monitor:
|
|
86
|
+
manager.run_monitoring_routine(wait_ms=2000)
|
|
87
|
+
if kill_upon_completion:
|
|
88
|
+
manager.kill_all_sessions()
|
|
89
|
+
if i < len(layouts_selected) - 1:
|
|
90
|
+
time.sleep(sleep_inbetween)
|
|
91
|
+
case "windows-terminal":
|
|
92
|
+
if sequential:
|
|
93
|
+
from machineconfig.cluster.sessions_managers.wt_local import run_wt_layout
|
|
94
|
+
for a_layout in layouts_selected:
|
|
95
|
+
run_wt_layout(layout_config=a_layout)
|
|
96
|
+
return
|
|
139
97
|
iterable = [layouts_selected]
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
from machineconfig.utils.schemas.layouts.layout_types import
|
|
156
|
-
|
|
157
|
-
for i in range(1, num_tabs + 1):
|
|
158
|
-
tab: TabConfig = {
|
|
159
|
-
"tabName": f"Tab{i}",
|
|
160
|
-
"startDir": "~/" + str(Path.cwd().relative_to(Path.home())),
|
|
161
|
-
"command": "bash",
|
|
162
|
-
}
|
|
163
|
-
tabs.append(tab)
|
|
164
|
-
layouts: list[LayoutConfig] = [
|
|
165
|
-
{
|
|
166
|
-
"layoutName": f"{Path.cwd().name}Layout",
|
|
167
|
-
"layoutTabs": tabs,
|
|
168
|
-
}
|
|
169
|
-
]
|
|
170
|
-
file: LayoutsFile = {
|
|
171
|
-
"$schema": "https://bit.ly/cfglayout", # type: ignore
|
|
172
|
-
"version": "0.1",
|
|
173
|
-
"layouts": layouts,
|
|
174
|
-
}
|
|
175
|
-
import json
|
|
176
|
-
json_string = json.dumps(file, indent=4)
|
|
177
|
-
if name is None:
|
|
178
|
-
layout_path = Path.cwd() / "layout.json"
|
|
179
|
-
else:
|
|
180
|
-
layout_path = Path.cwd() / (name.replace(".json", "") + ".json")
|
|
181
|
-
layout_path.parent.mkdir(parents=True, exist_ok=True)
|
|
182
|
-
if layout_path.exists():
|
|
183
|
-
print(f"❌ File {layout_path} already exists. Aborting to avoid overwriting.")
|
|
184
|
-
return
|
|
185
|
-
layout_path.write_text(json_string, encoding="utf-8")
|
|
186
|
-
print(f"✅ Created layout template at {layout_path}")
|
|
98
|
+
from machineconfig.cluster.sessions_managers.wt_local_manager import WTLocalManager
|
|
99
|
+
for i, a_layouts in enumerate(iterable):
|
|
100
|
+
manager = WTLocalManager(session_layouts=a_layouts)
|
|
101
|
+
manager.start_all_sessions()
|
|
102
|
+
if monitor:
|
|
103
|
+
manager.run_monitoring_routine(wait_ms=2000)
|
|
104
|
+
if kill_upon_completion:
|
|
105
|
+
manager.kill_all_sessions()
|
|
106
|
+
if i < len(layouts_selected) - 1:
|
|
107
|
+
time.sleep(sleep_inbetween)
|
|
108
|
+
case _:
|
|
109
|
+
raise ValueError(f"Unsupported backend: {backend}")
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
if __name__ == "__main__":
|
|
113
|
+
from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
|
|
114
|
+
_ = LayoutConfig
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Literal, Optional
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def balance_load(
|
|
6
|
+
layout_path: str,
|
|
7
|
+
max_thresh: int,
|
|
8
|
+
thresh_type: Literal["number", "n", "weight", "w"],
|
|
9
|
+
breaking_method: Literal["moreLayouts", "ml", "combineTabs", "ct"],
|
|
10
|
+
output_path: Optional[str],
|
|
11
|
+
) -> None:
|
|
12
|
+
"""Adjust layout file to limit max tabs per layout, etc."""
|
|
13
|
+
thresh_type_resolved: dict[str, Literal["number", "weight"]] = {"number": "number", "n": "number", "weight": "weight", "w": "weight"}
|
|
14
|
+
breaking_method_resolved: dict[str, Literal["moreLayouts", "combineTabs"]] = {"moreLayouts": "moreLayouts", "ml": "moreLayouts", "combineTabs": "combineTabs", "ct": "combineTabs"}
|
|
15
|
+
|
|
16
|
+
layout_path_obj = Path(layout_path).expanduser().absolute()
|
|
17
|
+
|
|
18
|
+
from machineconfig.utils.schemas.layouts.layout_types import LayoutsFile
|
|
19
|
+
import json
|
|
20
|
+
layoutfile: LayoutsFile = json.loads(layout_path_obj.read_text())
|
|
21
|
+
layout_configs = layoutfile["layouts"]
|
|
22
|
+
from machineconfig.cluster.sessions_managers.utils.load_balancer import limit_tab_num
|
|
23
|
+
new_layouts = limit_tab_num(layout_configs=layout_configs, max_thresh=max_thresh, threshold_type=thresh_type_resolved[thresh_type], breaking_method=breaking_method_resolved[breaking_method])
|
|
24
|
+
layoutfile["layouts"] = new_layouts
|
|
25
|
+
target_file = Path(output_path) if output_path is not None else layout_path_obj.parent / f"{layout_path_obj.stem}_adjusted_{max_thresh}_{thresh_type}_{breaking_method}.json"
|
|
26
|
+
target_file.parent.mkdir(parents=True, exist_ok=True)
|
|
27
|
+
target_file.write_text(data=json.dumps(layoutfile, indent=4), encoding="utf-8")
|
|
28
|
+
print(f"Adjusted layout saved to {target_file}")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def create_template(name: Optional[str], num_tabs: int) -> None:
|
|
32
|
+
"""Create a layout template file."""
|
|
33
|
+
from machineconfig.utils.schemas.layouts.layout_types import LayoutsFile, TabConfig, LayoutConfig
|
|
34
|
+
tabs: list[TabConfig] = []
|
|
35
|
+
import platform
|
|
36
|
+
if platform.system().lower() == "windows":
|
|
37
|
+
default_command = "powershell"
|
|
38
|
+
else:
|
|
39
|
+
default_command = "bash"
|
|
40
|
+
for i in range(1, num_tabs + 1):
|
|
41
|
+
tab: TabConfig = {
|
|
42
|
+
"tabName": f"Tab{i}",
|
|
43
|
+
"startDir": "~/" + str(Path.cwd().relative_to(Path.home())),
|
|
44
|
+
"command": default_command,
|
|
45
|
+
}
|
|
46
|
+
tabs.append(tab)
|
|
47
|
+
layouts: list[LayoutConfig] = [
|
|
48
|
+
{
|
|
49
|
+
"layoutName": f"{Path.cwd().name}Layout",
|
|
50
|
+
"layoutTabs": tabs,
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
file: LayoutsFile = {
|
|
54
|
+
"$schema": "https://bit.ly/cfglayout", # type: ignore
|
|
55
|
+
"version": "0.1",
|
|
56
|
+
"layouts": layouts,
|
|
57
|
+
}
|
|
58
|
+
import json
|
|
59
|
+
json_string = json.dumps(file, indent=4)
|
|
60
|
+
if name is None:
|
|
61
|
+
layout_path = Path.cwd() / "layout.json"
|
|
62
|
+
else:
|
|
63
|
+
layout_path = Path.cwd() / (name.replace(".json", "") + ".json")
|
|
64
|
+
layout_path.parent.mkdir(parents=True, exist_ok=True)
|
|
65
|
+
if layout_path.exists():
|
|
66
|
+
print(f"❌ File {layout_path} already exists. Aborting to avoid overwriting.")
|
|
67
|
+
return
|
|
68
|
+
layout_path.write_text(json_string, encoding="utf-8")
|
|
69
|
+
print(f"✅ Created layout template at {layout_path}")
|
|
@@ -100,11 +100,6 @@ def utils(ctx: typer.Context) -> None:
|
|
|
100
100
|
get_app()(ctx.args, standalone_mode=not ctx.args)
|
|
101
101
|
|
|
102
102
|
|
|
103
|
-
def terminal(ctx: typer.Context) -> None:
|
|
104
|
-
"""[t] Terminal management commands."""
|
|
105
|
-
from machineconfig.scripts.python.terminal import get_app
|
|
106
|
-
get_app()(ctx.args, standalone_mode=not ctx.args)
|
|
107
|
-
|
|
108
103
|
|
|
109
104
|
def get_app() -> typer.Typer:
|
|
110
105
|
app = typer.Typer(help="MachineConfig CLI - Manage your machine configurations and workflows", no_args_is_help=True, add_help_option=True, add_completion=False)
|
|
@@ -121,8 +116,6 @@ def get_app() -> typer.Typer:
|
|
|
121
116
|
app.command(name="a", hidden=True, context_settings=ctx_settings)(agents)
|
|
122
117
|
app.command(name="utils", help="[u] Utility commands", context_settings=ctx_settings)(utils)
|
|
123
118
|
app.command(name="u", hidden=True, context_settings=ctx_settings)(utils)
|
|
124
|
-
app.command(name="terminal", help="[t] Terminal management commands", context_settings=ctx_settings)(terminal)
|
|
125
|
-
app.command(name="t", hidden=True, context_settings=ctx_settings)(terminal)
|
|
126
119
|
|
|
127
120
|
app.command(name="fire", help="[f] Fire and manage jobs", no_args_is_help=False, context_settings={"allow_extra_args": True, "allow_interspersed_args": False})(fire)
|
|
128
121
|
app.command(name="f", hidden=True, no_args_is_help=False, context_settings={"allow_extra_args": True, "allow_interspersed_args": False})(fire)
|
|
@@ -12,44 +12,122 @@ def balance_load(
|
|
|
12
12
|
output_path: Annotated[Optional[str], typer.Option(..., "--output-path", "-o", help="Path to write the adjusted layout.json file")] = None,
|
|
13
13
|
) -> None:
|
|
14
14
|
"""Adjust layout file to limit max tabs per layout, etc."""
|
|
15
|
-
from machineconfig.scripts.python.helpers.helpers_sessions.
|
|
15
|
+
from machineconfig.scripts.python.helpers.helpers_sessions.utils import balance_load as impl
|
|
16
16
|
impl(layout_path=layout_path, max_thresh=max_thresh, thresh_type=thresh_type, breaking_method=breaking_method, output_path=output_path)
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def run(
|
|
20
20
|
ctx: typer.Context,
|
|
21
|
-
|
|
21
|
+
layouts_file: Annotated[Optional[str], typer.Option(..., "--layouts-file", "-f", help="Path to the layout.json file")] = None,
|
|
22
|
+
choose: Annotated[Optional[str], typer.Option(..., "--choose", "-c", help="Comma separated names of layouts to be selected from the layout file passed")] = None,
|
|
23
|
+
choose_interactively: Annotated[bool, typer.Option(..., "--choose-interactively", "-i", help="Select layouts interactively")] = False,
|
|
24
|
+
|
|
22
25
|
sleep_inbetween: Annotated[float, typer.Option(..., "--sleep-inbetween", "-si", help="Sleep time in seconds between launching layouts")] = 1.0,
|
|
23
26
|
monitor: Annotated[bool, typer.Option(..., "--monitor", "-m", help="Monitor the layout sessions for completion")] = False,
|
|
24
|
-
|
|
27
|
+
sequential: Annotated[bool, typer.Option(..., "--sequential", "-s", help="Launch layouts sequentially")] = False,
|
|
25
28
|
kill_upon_completion: Annotated[bool, typer.Option(..., "--kill-upon-completion", "-k", help="Kill session(s) upon completion (only relevant if monitor flag is set)")] = False,
|
|
26
|
-
choose: Annotated[Optional[str], typer.Option(..., "--choose", "-c", help="Comma separated names of layouts to be selected from the layout file passed")] = None,
|
|
27
|
-
choose_interactively: Annotated[bool, typer.Option(..., "--choose-interactively", "-i", help="Select layouts interactively")] = False,
|
|
28
29
|
subsitute_home: Annotated[bool, typer.Option(..., "--substitute-home", "-sh", help="Substitute ~ and $HOME in layout file with actual home directory path")] = False,
|
|
29
30
|
max_tabs: Annotated[int, typer.Option(..., "--max-tabs", "-mt", help="A Sanity checker that throws an error if any layout exceeds the maximum number of tabs to launch.")] = 25,
|
|
30
31
|
max_layouts: Annotated[int, typer.Option(..., "--max-layouts", "-ml", help="A Sanity checker that throws an error if the total number of *parallel layouts exceeds this number.")] = 25,
|
|
32
|
+
backend: Annotated[Literal["zellij", "z", "windows-terminal", "wt", "auto", "a"], typer.Option(..., "--backend", "-b", help="Backend terminal multiplexer or emulator to use")] = "auto",
|
|
31
33
|
) -> None:
|
|
32
34
|
"""Launch terminal sessions based on a layout configuration file."""
|
|
33
|
-
|
|
35
|
+
from machineconfig.scripts.python.helpers.helpers_sessions.sessions_impl import run_layouts, find_layout_file, select_layout
|
|
36
|
+
|
|
37
|
+
from pathlib import Path
|
|
38
|
+
if layouts_file is not None:
|
|
39
|
+
layouts_file_resolved = Path(find_layout_file(layout_path=layouts_file))
|
|
40
|
+
else:
|
|
41
|
+
layouts_file_resolved = Path.home().joinpath("dotfiles/machineconfig/layouts.json")
|
|
42
|
+
if not layouts_file_resolved.exists():
|
|
34
43
|
typer.echo(ctx.get_help())
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
typer.echo(f"❌ Layouts file not found: {layouts_file_resolved}", err=True)
|
|
45
|
+
raise typer.Exit(code=1)
|
|
46
|
+
|
|
47
|
+
if choose is None: layouts_names_resolved: list[str] = []
|
|
48
|
+
else: layouts_names_resolved = [name.strip() for name in choose.split(",") if name.strip()]
|
|
49
|
+
layouts_selected = select_layout(layouts_json_file=str(layouts_file_resolved), selected_layouts_names=layouts_names_resolved,
|
|
50
|
+
select_interactively=choose_interactively,)
|
|
51
|
+
if subsitute_home:
|
|
52
|
+
from machineconfig.utils.schemas.layouts.layout_types import substitute_home, LayoutConfig
|
|
53
|
+
layouts_modified: list["LayoutConfig"] = []
|
|
54
|
+
for a_layout in layouts_selected:
|
|
55
|
+
a_layout["layoutTabs"] = substitute_home(tabs=a_layout["layoutTabs"])
|
|
56
|
+
layouts_modified.append(a_layout)
|
|
57
|
+
layouts_selected = layouts_modified
|
|
58
|
+
|
|
59
|
+
import platform
|
|
60
|
+
backend_resolved: Literal["zellij", "windows-terminal"]
|
|
61
|
+
match backend:
|
|
62
|
+
case "windows-terminal" | "wt":
|
|
63
|
+
if platform.system().lower() != "windows":
|
|
64
|
+
typer.echo("Error: Windows Terminal layouts can only be started on Windows systems.", err=True)
|
|
65
|
+
raise typer.Exit(code=1)
|
|
66
|
+
backend_resolved = "windows-terminal"
|
|
67
|
+
case "zellij" | "z":
|
|
68
|
+
if platform.system().lower() == "windows":
|
|
69
|
+
typer.echo("Error: Zellij is not supported on Windows.", err=True)
|
|
70
|
+
raise typer.Exit(code=1)
|
|
71
|
+
backend_resolved = "zellij"
|
|
72
|
+
case "auto" | "a":
|
|
73
|
+
if platform.system().lower() == "windows":
|
|
74
|
+
backend_resolved = "windows-terminal"
|
|
75
|
+
else:
|
|
76
|
+
backend_resolved = "zellij"
|
|
77
|
+
case _:
|
|
78
|
+
typer.echo(f"Error: Unsupported backend '{backend}'.", err=True)
|
|
79
|
+
raise typer.Exit(code=1)
|
|
80
|
+
|
|
81
|
+
if not sequential and len(layouts_selected) > max_layouts:
|
|
82
|
+
raise ValueError(f"Number of layouts {len(layouts_selected)} exceeds the maximum allowed {max_layouts}. Please adjust your layout file.")
|
|
83
|
+
for a_layout in layouts_selected:
|
|
84
|
+
if len(a_layout["layoutTabs"]) > max_tabs:
|
|
85
|
+
raise ValueError(f"Layout '{a_layout.get('layoutName', 'Unnamed')}' has {len(a_layout['layoutTabs'])} tabs which exceeds the max of {max_tabs}.")
|
|
86
|
+
|
|
37
87
|
try:
|
|
38
|
-
run_layouts(
|
|
88
|
+
run_layouts(
|
|
89
|
+
sleep_inbetween=sleep_inbetween, monitor=monitor, sequential=sequential, kill_upon_completion=kill_upon_completion,
|
|
90
|
+
layouts_selected=layouts_selected,
|
|
91
|
+
backend=backend_resolved)
|
|
39
92
|
except ValueError as e:
|
|
40
93
|
typer.echo(str(e))
|
|
41
94
|
raise typer.Exit(1) from e
|
|
42
95
|
|
|
43
96
|
|
|
97
|
+
def attach_to_session(
|
|
98
|
+
name: Annotated[str | None, typer.Argument(help="Name of the Zellij session to attach to. If not provided, a list will be shown to choose from.")] = None,
|
|
99
|
+
new_session: Annotated[bool, typer.Option("--new-session", "-n", help="Create a new Zellij session instead of attaching to an existing one.", show_default=True)] = False,
|
|
100
|
+
kill_all: Annotated[bool, typer.Option("--kill-all", "-k", help="Kill all existing Zellij sessions before creating a new one.", show_default=True)] = False) -> None:
|
|
101
|
+
"""Choose a Zellij session to attach to."""
|
|
102
|
+
import platform
|
|
103
|
+
if platform.system().lower() == "windows":
|
|
104
|
+
typer.echo("Error: Zellij is not supported on Windows.", err=True, color=True)
|
|
105
|
+
raise typer.Exit()
|
|
106
|
+
from machineconfig.scripts.python.helpers.helpers_sessions.attach_impl import choose_zellij_session as impl
|
|
107
|
+
action, payload = impl(name=name, new_session=new_session, kill_all=kill_all)
|
|
108
|
+
if action == "error":
|
|
109
|
+
typer.echo(payload, err=True, color=True)
|
|
110
|
+
raise typer.Exit()
|
|
111
|
+
if action == "run_script" and payload:
|
|
112
|
+
from machineconfig.utils.code import exit_then_run_shell_script
|
|
113
|
+
exit_then_run_shell_script(script= payload, strict=True)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def get_session_tabs() -> list[tuple[str, str]]:
|
|
118
|
+
"""Get all Zellij session tabs."""
|
|
119
|
+
from machineconfig.scripts.python.helpers.helpers_sessions.attach_impl import get_session_tabs as impl
|
|
120
|
+
result = impl()
|
|
121
|
+
print(result)
|
|
122
|
+
return result
|
|
44
123
|
def create_template(
|
|
45
124
|
name: Annotated[Optional[str], typer.Argument(..., help="Name of the layout template to create")] = None,
|
|
46
125
|
num_tabs: Annotated[int, typer.Option(..., "--num-tabs", "-t", help="Number of tabs to include in the template")] = 3,
|
|
47
126
|
) -> None:
|
|
48
127
|
"""Create a layout template file."""
|
|
49
|
-
from machineconfig.scripts.python.helpers.helpers_sessions.
|
|
128
|
+
from machineconfig.scripts.python.helpers.helpers_sessions.utils import create_template as impl
|
|
50
129
|
impl(name=name, num_tabs=num_tabs)
|
|
51
130
|
|
|
52
|
-
|
|
53
131
|
def create_from_function(
|
|
54
132
|
num_process: Annotated[int, typer.Option(..., "--num-process", "-n", help="Number of parallel processes to run")],
|
|
55
133
|
path: Annotated[str, typer.Option(..., "--path", "-p", help="Path to a Python or Shell script file or a directory containing such files")] = ".",
|
|
@@ -63,12 +141,15 @@ def create_from_function(
|
|
|
63
141
|
def get_app() -> typer.Typer:
|
|
64
142
|
layouts_app = typer.Typer(help="Layouts management subcommands", no_args_is_help=True, add_help_option=True, add_completion=False)
|
|
65
143
|
|
|
66
|
-
layouts_app.command("create-from-function", no_args_is_help=True, short_help="[c] Create a layout from a function")(create_from_function)
|
|
67
|
-
layouts_app.command("c", no_args_is_help=True, hidden=True)(create_from_function)
|
|
68
|
-
|
|
69
144
|
layouts_app.command("run", no_args_is_help=True, help=run.__doc__, short_help="[r] Run the selected layout(s)")(run)
|
|
70
145
|
layouts_app.command("r", no_args_is_help=True, help=run.__doc__, hidden=True)(run)
|
|
71
146
|
|
|
147
|
+
layouts_app.command("attach", no_args_is_help=False, help=attach_to_session.__doc__, short_help="[a] Attach to a Zellij session")(attach_to_session)
|
|
148
|
+
layouts_app.command("a", no_args_is_help=False, help=attach_to_session.__doc__, hidden=True)(attach_to_session)
|
|
149
|
+
|
|
150
|
+
layouts_app.command("create-from-function", no_args_is_help=True, short_help="[c] Create a layout from a function")(create_from_function)
|
|
151
|
+
layouts_app.command("c", no_args_is_help=True, hidden=True)(create_from_function)
|
|
152
|
+
|
|
72
153
|
layouts_app.command("balance-load", no_args_is_help=True, help=balance_load.__doc__, short_help="[b] Balance the load across sessions")(balance_load)
|
|
73
154
|
layouts_app.command("b", no_args_is_help=True, help=balance_load.__doc__, hidden=True)(balance_load)
|
|
74
155
|
|
|
@@ -6,9 +6,10 @@ from typing import Annotated, Optional, Literal
|
|
|
6
6
|
|
|
7
7
|
def kill_process(interactive: Annotated[bool, typer.Option(..., "--interactive", "-i", help="Interactively choose the process to kill")] = True) -> None:
|
|
8
8
|
"""⚔️ Choose a process to kill."""
|
|
9
|
-
from machineconfig.utils.procs import
|
|
9
|
+
from machineconfig.utils.procs import ProcessManager
|
|
10
10
|
if interactive:
|
|
11
|
-
|
|
11
|
+
proc = ProcessManager()
|
|
12
|
+
proc.choose_and_kill()
|
|
12
13
|
return
|
|
13
14
|
_ = ProcessManager
|
|
14
15
|
|
|
@@ -56,7 +56,6 @@ alias fx='wrap_in_shell_script ftpx'
|
|
|
56
56
|
alias f='wrap_in_shell_script fire'
|
|
57
57
|
alias r='wrap_in_shell_script croshell'
|
|
58
58
|
alias u='wrap_in_shell_script utils'
|
|
59
|
-
alias t='wrap_in_shell_script terminal'
|
|
60
59
|
alias ms='wrap_in_shell_script msearch'
|
|
61
60
|
alias x='wrap_in_shell_script explore'
|
|
62
61
|
|
|
@@ -73,12 +72,6 @@ alias x='wrap_in_shell_script explore'
|
|
|
73
72
|
# gh copilot explain "Input command is: $x The output is this: $y"
|
|
74
73
|
# }
|
|
75
74
|
|
|
76
|
-
# 📦 Node Version Manager
|
|
77
|
-
# export NVM_DIR="$HOME/.nvm"
|
|
78
|
-
# [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
|
|
79
|
-
# [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
|
|
80
|
-
|
|
81
|
-
|
|
82
75
|
# https://github.com/atuinsh/atuin
|
|
83
76
|
# eval "$(atuin init bash)"
|
|
84
77
|
|
|
@@ -40,12 +40,11 @@ if (Test-Path "$CONFIG_ROOT\scripts\wrap_mcfg.ps1") {
|
|
|
40
40
|
function d { wrap_in_shell_script devops $args }
|
|
41
41
|
function c { wrap_in_shell_script cloud $args }
|
|
42
42
|
function a { wrap_in_shell_script agents $args }
|
|
43
|
-
function sx { wrap_in_shell_script sessions $args }
|
|
44
43
|
function fx { wrap_in_shell_script ftpx $args }
|
|
44
|
+
function s { wrap_in_shell_script sessions $args }
|
|
45
45
|
function f { wrap_in_shell_script fire $args }
|
|
46
46
|
function rr { wrap_in_shell_script croshell $args }
|
|
47
47
|
function u { wrap_in_shell_script utils $args }
|
|
48
|
-
function t { wrap_in_shell_script terminal $args }
|
|
49
48
|
function ms { wrap_in_shell_script msearch $args }
|
|
50
49
|
|
|
51
50
|
}
|
|
@@ -56,12 +55,11 @@ else {
|
|
|
56
55
|
function d { devops $args }
|
|
57
56
|
function c { cloud $args }
|
|
58
57
|
function a { agents $args }
|
|
59
|
-
function
|
|
58
|
+
function s { sessions $args }
|
|
60
59
|
function fx { ftpx $args }
|
|
61
60
|
function f { fire $args }
|
|
62
61
|
function rr { croshell $args }
|
|
63
62
|
function u { utils $args }
|
|
64
|
-
function t { terminal $args }
|
|
65
63
|
function ms { msearch $args }
|
|
66
64
|
}
|
|
67
65
|
|
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
"copyOnSelect": true,
|
|
7
7
|
"defaultProfile": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
|
|
8
8
|
"focusFollowMouse": true,
|
|
9
|
-
"keybindings":
|
|
10
|
-
[
|
|
9
|
+
"keybindings": [
|
|
11
10
|
{
|
|
12
11
|
"id": "Terminal.FindText",
|
|
13
12
|
"keys": "ctrl+shift+f"
|
|
@@ -38,28 +37,26 @@
|
|
|
38
37
|
}
|
|
39
38
|
],
|
|
40
39
|
"launchMode": "fullscreen",
|
|
41
|
-
"newTabMenu":
|
|
42
|
-
[
|
|
40
|
+
"newTabMenu": [
|
|
43
41
|
{
|
|
44
42
|
"type": "remainingProfiles"
|
|
45
43
|
}
|
|
46
44
|
],
|
|
47
|
-
"profiles":
|
|
48
|
-
|
|
49
|
-
"defaults":
|
|
50
|
-
{
|
|
45
|
+
"profiles": {
|
|
46
|
+
"defaults": {
|
|
51
47
|
"colorScheme": "Campbell (modified)",
|
|
52
48
|
"padding": "0",
|
|
53
|
-
"useAcrylic": false
|
|
49
|
+
"useAcrylic": false,
|
|
50
|
+
"font": {
|
|
51
|
+
"face": "CaskaydiaCove Nerd Font"
|
|
52
|
+
}
|
|
54
53
|
},
|
|
55
|
-
"list":
|
|
56
|
-
[
|
|
54
|
+
"list": [
|
|
57
55
|
{
|
|
58
56
|
"commandline": "C:\\Program Files\\PowerShell\\7\\pwsh.exe",
|
|
59
57
|
"cursorColor": "#D4D8E1",
|
|
60
58
|
"cursorShape": "filledBox",
|
|
61
|
-
"font":
|
|
62
|
-
{
|
|
59
|
+
"font": {
|
|
63
60
|
"face": "CaskaydiaCove Nerd Font"
|
|
64
61
|
},
|
|
65
62
|
"guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
|
|
@@ -71,8 +68,7 @@
|
|
|
71
68
|
},
|
|
72
69
|
{
|
|
73
70
|
"commandline": "%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
|
|
74
|
-
"font":
|
|
75
|
-
{
|
|
71
|
+
"font": {
|
|
76
72
|
"face": "CaskaydiaCove Nerd Font"
|
|
77
73
|
},
|
|
78
74
|
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
|
|
@@ -93,8 +89,7 @@
|
|
|
93
89
|
},
|
|
94
90
|
{
|
|
95
91
|
"commandline": "nu.exe",
|
|
96
|
-
"font":
|
|
97
|
-
{
|
|
92
|
+
"font": {
|
|
98
93
|
"face": "CaskaydiaCove Nerd Font"
|
|
99
94
|
},
|
|
100
95
|
"guid": "{4b9d9cef-cb7d-4a8c-8b08-0de52621c3ff}",
|
|
@@ -157,8 +152,7 @@
|
|
|
157
152
|
}
|
|
158
153
|
]
|
|
159
154
|
},
|
|
160
|
-
"schemes":
|
|
161
|
-
[
|
|
155
|
+
"schemes": [
|
|
162
156
|
{
|
|
163
157
|
"background": "#000000",
|
|
164
158
|
"black": "#000000",
|
|
@@ -59,7 +59,6 @@ alias fx='wrap_in_shell_script ftpx'
|
|
|
59
59
|
alias f='wrap_in_shell_script fire'
|
|
60
60
|
alias r='wrap_in_shell_script croshell'
|
|
61
61
|
alias u='wrap_in_shell_script utils'
|
|
62
|
-
alias t='wrap_in_shell_script terminal'
|
|
63
62
|
alias ms='wrap_in_shell_script msearch'
|
|
64
63
|
alias x='. $CONFIG_ROOT/scripts/wrap_mcfg explore'
|
|
65
64
|
|
|
File without changes
|