machineconfig 3.3__py3-none-any.whl → 3.7__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/cluster/remote/cloud_manager.py +1 -1
- machineconfig/cluster/sessions_managers/wt_local_manager.py +1 -1
- machineconfig/cluster/sessions_managers/wt_remote_manager.py +1 -1
- machineconfig/cluster/sessions_managers/zellij_local_manager.py +1 -1
- machineconfig/cluster/sessions_managers/zellij_remote_manager.py +1 -1
- machineconfig/cluster/templates/utils.py +1 -1
- machineconfig/jobs/linux/msc/cli_agents.sh +18 -2
- machineconfig/jobs/python/python_ve_symlink.py +2 -2
- machineconfig/jobs/python/vscode/api.py +1 -1
- machineconfig/jobs/python/vscode/select_interpreter.py +2 -2
- machineconfig/jobs/python/vscode/sync_code.py +1 -1
- machineconfig/jobs/python_custom_installers/dev/bypass_paywall.py +1 -1
- machineconfig/jobs/python_custom_installers/dev/espanso.py +1 -1
- machineconfig/jobs/python_custom_installers/hx.py +1 -1
- machineconfig/jobs/python_generic_installers/config.json +0 -11
- machineconfig/profile/create.py +6 -6
- machineconfig/profile/shell.py +3 -3
- machineconfig/scripts/python/ai/mcinit.py +23 -67
- machineconfig/scripts/python/ai/solutions/__init__.py +0 -0
- machineconfig/scripts/python/ai/solutions/_shared.py +5 -0
- machineconfig/scripts/python/ai/solutions/claude/claude.py +8 -0
- machineconfig/scripts/python/ai/solutions/cline/cline.py +10 -0
- machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +35 -0
- machineconfig/scripts/python/ai/solutions/copilot/privacy.md +4 -0
- machineconfig/scripts/python/ai/solutions/crush/crush.json +216 -0
- machineconfig/scripts/python/ai/solutions/crush/crush.py +25 -0
- machineconfig/scripts/python/ai/solutions/crush/privacy.md +2 -0
- machineconfig/scripts/python/ai/solutions/cursor/cursors.py +10 -0
- machineconfig/scripts/python/ai/solutions/gemini/gemini.py +14 -0
- machineconfig/scripts/python/ai/solutions/generic.py +41 -0
- machineconfig/scripts/python/ai/solutions/kilocode/privacy.md +3 -0
- machineconfig/scripts/python/ai/solutions/opencode/opencode.json +4 -0
- machineconfig/scripts/python/ai/solutions/opencode/opencode.py +1 -0
- machineconfig/scripts/python/choose_wezterm_theme.py +3 -3
- machineconfig/scripts/python/cloud_copy.py +2 -2
- machineconfig/scripts/python/cloud_mount.py +4 -4
- machineconfig/scripts/python/cloud_repo_sync.py +5 -4
- machineconfig/scripts/python/croshell.py +14 -9
- machineconfig/scripts/python/devops.py +2 -2
- machineconfig/scripts/python/devops_add_identity.py +4 -9
- machineconfig/scripts/python/devops_add_ssh_key.py +3 -5
- machineconfig/scripts/python/devops_backup_retrieve.py +6 -5
- machineconfig/scripts/python/devops_devapps_install.py +4 -4
- machineconfig/scripts/python/devops_update_repos.py +2 -2
- machineconfig/scripts/python/dotfile.py +1 -1
- machineconfig/scripts/python/fire_agents.py +7 -7
- machineconfig/scripts/python/fire_agents_help_launch.py +2 -2
- machineconfig/scripts/python/fire_jobs.py +13 -13
- machineconfig/scripts/python/fire_jobs_layout_helper.py +6 -6
- machineconfig/scripts/python/ftpx.py +2 -2
- machineconfig/scripts/python/helpers/cloud_helpers.py +2 -1
- machineconfig/scripts/python/helpers/helpers2.py +4 -3
- machineconfig/scripts/python/helpers/helpers4.py +1 -1
- machineconfig/scripts/python/helpers/repo_sync_helpers.py +2 -2
- machineconfig/scripts/python/mount_nfs.py +4 -4
- machineconfig/scripts/python/mount_ssh.py +1 -1
- machineconfig/scripts/python/repos.py +6 -3
- machineconfig/scripts/python/repos_helper_clone.py +121 -0
- machineconfig/scripts/python/repos_helper_record.py +2 -2
- machineconfig/scripts/python/start_slidev.py +1 -1
- machineconfig/scripts/python/start_terminals.py +2 -2
- machineconfig/scripts/python/wsl_windows_transfer.py +1 -1
- machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +2 -2
- machineconfig/setup_windows/wt_and_pwsh/install_nerd_fonts.py +1 -1
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +3 -3
- machineconfig/utils/{utils2.py → accessories.py} +13 -29
- machineconfig/utils/code.py +2 -2
- machineconfig/utils/installer.py +2 -2
- machineconfig/utils/installer_utils/installer_abc.py +1 -1
- machineconfig/utils/installer_utils/installer_class.py +5 -5
- machineconfig/utils/io.py +94 -0
- machineconfig/utils/links.py +2 -2
- machineconfig/utils/notifications.py +0 -9
- machineconfig/utils/options.py +25 -18
- machineconfig/utils/{path_reduced.py → path_extended.py} +1 -1
- machineconfig/utils/{path.py → path_helper.py} +3 -3
- machineconfig/utils/procs.py +3 -3
- machineconfig/utils/{utils5.py → scheduler.py} +3 -8
- machineconfig/utils/scheduling.py +2 -2
- machineconfig/utils/ssh.py +2 -2
- machineconfig/utils/terminal.py +12 -2
- machineconfig/utils/ve.py +2 -16
- {machineconfig-3.3.dist-info → machineconfig-3.7.dist-info}/METADATA +1 -4
- {machineconfig-3.3.dist-info → machineconfig-3.7.dist-info}/RECORD +94 -78
- machineconfig/utils/io_save.py +0 -95
- /machineconfig/scripts/python/ai/{chatmodes → solutions/copilot/chatmodes}/Thinking-Beast-Mode.chatmode.md +0 -0
- /machineconfig/scripts/python/ai/{chatmodes → solutions/copilot/chatmodes}/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md +0 -0
- /machineconfig/scripts/python/ai/{chatmodes → solutions/copilot/chatmodes}/deepResearch.chatmode.md +0 -0
- /machineconfig/scripts/python/ai/{instructions → solutions/copilot/instructions}/python/dev.instructions.md +0 -0
- /machineconfig/scripts/python/ai/{prompts → solutions/copilot/prompts}/allLintersAndTypeCheckers.prompt.md +0 -0
- /machineconfig/scripts/python/ai/{prompts → solutions/copilot/prompts}/research-report-skeleton.prompt.md +0 -0
- /machineconfig/scripts/python/ai/{configs/.gemini → solutions/gemini}/settings.json +0 -0
- {machineconfig-3.3.dist-info → machineconfig-3.7.dist-info}/WHEEL +0 -0
- {machineconfig-3.3.dist-info → machineconfig-3.7.dist-info}/entry_points.txt +0 -0
- {machineconfig-3.3.dist-info → machineconfig-3.7.dist-info}/top_level.txt +0 -0
|
@@ -15,9 +15,9 @@ import sys
|
|
|
15
15
|
from machineconfig.scripts.python.fire_agents_help_launch import prep_agent_launch, get_agents_launch_layout, AGENTS
|
|
16
16
|
from machineconfig.scripts.python.fire_agents_help_search import search_files_by_pattern, search_python_files
|
|
17
17
|
from machineconfig.scripts.python.fire_agents_load_balancer import chunk_prompts, SPLITTING_STRATEGY, DEFAULT_AGENT_CAP
|
|
18
|
-
from machineconfig.utils.options import
|
|
18
|
+
from machineconfig.utils.options import choose_from_options
|
|
19
19
|
from machineconfig.utils.schemas.layouts.layout_types import TabConfig, LayoutConfig
|
|
20
|
-
from machineconfig.utils.
|
|
20
|
+
from machineconfig.utils.accessories import get_repo_root
|
|
21
21
|
|
|
22
22
|
SEARCH_STRATEGIES: TypeAlias = Literal["file_path", "keyword_search", "filename_pattern"]
|
|
23
23
|
|
|
@@ -80,9 +80,9 @@ def main(): # noqa: C901 - (complexity acceptable for CLI glue)
|
|
|
80
80
|
sys.exit(1)
|
|
81
81
|
print(f"Operating @ {repo_root}")
|
|
82
82
|
|
|
83
|
-
search_strategy = cast(SEARCH_STRATEGIES,
|
|
84
|
-
splitting_strategy = cast(SPLITTING_STRATEGY,
|
|
85
|
-
agent_selected = cast(AGENTS,
|
|
83
|
+
search_strategy = cast(SEARCH_STRATEGIES, choose_from_options(multi=False, msg="Choose one option", header="Choose search strategy:", options=get_args(SEARCH_STRATEGIES)))
|
|
84
|
+
splitting_strategy = cast(SPLITTING_STRATEGY, choose_from_options(multi=False, msg="Choose one option", header="Choose prompt splitting strategy:", options=get_args(SPLITTING_STRATEGY)))
|
|
85
|
+
agent_selected = cast(AGENTS, choose_from_options(multi=False, msg="Choose one option", header="Select agent type", options=get_args(AGENTS)))
|
|
86
86
|
print("Enter prefix prompt (end with Ctrl-D / Ctrl-Z):")
|
|
87
87
|
prompt_prefix = "\n".join(sys.stdin.readlines())
|
|
88
88
|
job_name = input("Enter job name [AI_AGENTS]: ") or "AI_Agents"
|
|
@@ -151,7 +151,7 @@ manager.run_monitoring_routine()
|
|
|
151
151
|
|
|
152
152
|
|
|
153
153
|
def split_too_many_tabs_to_run_in_sequential_sessions(layout_tabs: list[TabConfig], every: int):
|
|
154
|
-
from machineconfig.utils.
|
|
154
|
+
from machineconfig.utils.accessories import split
|
|
155
155
|
from machineconfig.cluster.sessions_managers.zellij_local_manager import ZellijLocalManager
|
|
156
156
|
|
|
157
157
|
for idx, layout_tabs_chunk in enumerate(split(layout_tabs, every=every)):
|
|
@@ -163,7 +163,7 @@ def split_too_many_tabs_to_run_in_sequential_sessions(layout_tabs: list[TabConfi
|
|
|
163
163
|
|
|
164
164
|
|
|
165
165
|
def split_too_many_layouts_to_run_in_sequential_sessions(layouts: list[LayoutConfig], every: int):
|
|
166
|
-
from machineconfig.utils.
|
|
166
|
+
from machineconfig.utils.accessories import split
|
|
167
167
|
from machineconfig.cluster.sessions_managers.zellij_local_manager import ZellijLocalManager
|
|
168
168
|
|
|
169
169
|
for _idx, layout_chunk in enumerate(split(layouts, every=every)):
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from machineconfig.utils.
|
|
1
|
+
from machineconfig.utils.accessories import randstr
|
|
2
2
|
|
|
3
3
|
import random
|
|
4
4
|
import shlex
|
|
@@ -14,7 +14,7 @@ AGENT_NAME_FORMATTER = "agent_{idx}_cmd.sh" # e.g., agent_0_cmd.sh
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def get_gemini_api_keys() -> list[str]:
|
|
17
|
-
from machineconfig.utils.
|
|
17
|
+
from machineconfig.utils.io import read_ini
|
|
18
18
|
|
|
19
19
|
config = read_ini(Path.home().joinpath("dotfiles/creds/llm/gemini/api_keys.ini"))
|
|
20
20
|
res: list[str] = []
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
fire
|
|
3
3
|
|
|
4
4
|
# https://github.com/pallets/click combine with fire. Consider
|
|
5
|
-
# https://github.com/ceccopierangiolieugenio/pyTermTk for
|
|
5
|
+
# https://github.com/ceccopierangiolieugenio/pyTermTk for choose_from_options build TUI
|
|
6
6
|
# https://github.com/chriskiehl/Gooey build commandline interface
|
|
7
7
|
|
|
8
8
|
"""
|
|
@@ -11,17 +11,17 @@ from machineconfig.scripts.python.helpers.helpers4 import search_for_files_of_in
|
|
|
11
11
|
from machineconfig.scripts.python.helpers.helpers4 import convert_kwargs_to_fire_kwargs_str
|
|
12
12
|
from machineconfig.scripts.python.helpers.helpers4 import parse_pyfile
|
|
13
13
|
from machineconfig.scripts.python.helpers.helpers4 import get_import_module_code
|
|
14
|
-
from machineconfig.utils.ve import
|
|
15
|
-
from machineconfig.utils.options import
|
|
16
|
-
from machineconfig.utils.
|
|
14
|
+
from machineconfig.utils.ve import get_ve_activate_line, get_ve_path_and_ipython_profile
|
|
15
|
+
from machineconfig.utils.options import choose_from_options
|
|
16
|
+
from machineconfig.utils.path_helper import match_file_name, sanitize_path
|
|
17
17
|
|
|
18
|
-
from machineconfig.utils.
|
|
19
|
-
from machineconfig.utils.
|
|
20
|
-
from machineconfig.utils.utils2 import randstr, read_toml
|
|
18
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
19
|
+
from machineconfig.utils.accessories import get_repo_root, randstr
|
|
21
20
|
from machineconfig.scripts.python.fire_jobs_args_helper import get_args, FireJobArgs, extract_kwargs
|
|
22
21
|
import platform
|
|
23
22
|
from typing import Optional
|
|
24
23
|
from pathlib import Path
|
|
24
|
+
import tomllib
|
|
25
25
|
# import os
|
|
26
26
|
|
|
27
27
|
|
|
@@ -39,7 +39,7 @@ def route(args: FireJobArgs) -> None:
|
|
|
39
39
|
print(f"🔍 Searching recursively for Python, PowerShell and Shell scripts in directory `{path_obj}`")
|
|
40
40
|
files = search_for_files_of_interest(path_obj)
|
|
41
41
|
print(f"🔍 Got #{len(files)} results.")
|
|
42
|
-
choice_file =
|
|
42
|
+
choice_file = choose_from_options(multi=False, options=files, fzf=True, msg="Choose one option")
|
|
43
43
|
choice_file = PathExtended(choice_file)
|
|
44
44
|
else:
|
|
45
45
|
choice_file = path_obj
|
|
@@ -60,7 +60,7 @@ def route(args: FireJobArgs) -> None:
|
|
|
60
60
|
if args.choose_function or args.submit_to_cloud:
|
|
61
61
|
if choice_file.suffix == ".py":
|
|
62
62
|
options, func_args = parse_pyfile(file_path=str(choice_file))
|
|
63
|
-
choice_function_tmp =
|
|
63
|
+
choice_function_tmp = choose_from_options(msg="Choose a function to run", options=options, fzf=True, multi=False)
|
|
64
64
|
assert isinstance(choice_function_tmp, str), f"choice_function must be a string. Got {type(choice_function_tmp)}"
|
|
65
65
|
choice_index = options.index(choice_function_tmp)
|
|
66
66
|
choice_function = choice_function_tmp.split(" -- ")[0]
|
|
@@ -81,7 +81,7 @@ def route(args: FireJobArgs) -> None:
|
|
|
81
81
|
if line.startswith("echo"):
|
|
82
82
|
continue
|
|
83
83
|
options.append(line)
|
|
84
|
-
chosen_lines =
|
|
84
|
+
chosen_lines = choose_from_options(msg="Choose a line to run", options=options, fzf=True, multi=True)
|
|
85
85
|
choice_file = PathExtended.tmpfile(suffix=".sh")
|
|
86
86
|
choice_file.parent.mkdir(parents=True, exist_ok=True)
|
|
87
87
|
choice_file.write_text("\n".join(chosen_lines), encoding="utf-8")
|
|
@@ -113,7 +113,7 @@ def route(args: FireJobArgs) -> None:
|
|
|
113
113
|
toml_path = toml_path_maybe
|
|
114
114
|
if toml_path is not None:
|
|
115
115
|
print(f"📄 Reading config.toml @ {toml_path}")
|
|
116
|
-
config =
|
|
116
|
+
config = tomllib.loads(toml_path.read_text(encoding="utf-8"))
|
|
117
117
|
if "server" in config:
|
|
118
118
|
if "port" in config["server"]:
|
|
119
119
|
port = config["server"]["port"]
|
|
@@ -121,7 +121,7 @@ def route(args: FireJobArgs) -> None:
|
|
|
121
121
|
if repo_root is not None:
|
|
122
122
|
secrets_template_path = PathExtended.home().joinpath(f"dotfiles/creds/streamlit/{PathExtended(repo_root).name}/{choice_file.name}/secrets.toml")
|
|
123
123
|
if args.environment != "" and not secrets_path.exists() and secrets_template_path.exists():
|
|
124
|
-
secrets_template =
|
|
124
|
+
secrets_template = tomllib.loads(secrets_template_path.read_text(encoding="utf-8"))
|
|
125
125
|
if args.environment == "ip":
|
|
126
126
|
host_url = f"http://{local_ip_v4}:{port}/oauth2callback"
|
|
127
127
|
elif args.environment == "localhost":
|
|
@@ -134,7 +134,7 @@ def route(args: FireJobArgs) -> None:
|
|
|
134
134
|
secrets_template["auth"]["redirect_uri"] = host_url
|
|
135
135
|
secrets_template["auth"]["cookie_secret"] = randstr(35)
|
|
136
136
|
secrets_template["auth"]["auth0"]["redirect_uri"] = host_url
|
|
137
|
-
save_toml(obj=secrets_template, path=secrets_path)
|
|
137
|
+
# save_toml(obj=secrets_template, path=secrets_path)
|
|
138
138
|
except Exception as ex:
|
|
139
139
|
print(ex)
|
|
140
140
|
raise ex
|
|
@@ -2,9 +2,9 @@ from pathlib import Path
|
|
|
2
2
|
from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig, LayoutsFile
|
|
3
3
|
from typing import Optional, TYPE_CHECKING
|
|
4
4
|
from machineconfig.scripts.python.helpers.helpers4 import search_for_files_of_interest
|
|
5
|
-
from machineconfig.utils.options import
|
|
6
|
-
from machineconfig.utils.
|
|
7
|
-
from machineconfig.utils.
|
|
5
|
+
from machineconfig.utils.options import choose_from_options
|
|
6
|
+
from machineconfig.utils.path_helper import match_file_name, sanitize_path
|
|
7
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
8
8
|
|
|
9
9
|
if TYPE_CHECKING:
|
|
10
10
|
from machineconfig.scripts.python.fire_jobs_args_helper import FireJobArgs
|
|
@@ -18,9 +18,9 @@ def select_layout(layouts_json_file: Path, layout_name: Optional[str]):
|
|
|
18
18
|
raise ValueError(f"No layouts found in {layouts_json_file}")
|
|
19
19
|
if layout_name is None:
|
|
20
20
|
options = [layout["layoutName"] for layout in layout_file["layouts"]]
|
|
21
|
-
from machineconfig.utils.options import
|
|
21
|
+
from machineconfig.utils.options import choose_from_options
|
|
22
22
|
|
|
23
|
-
layout_name =
|
|
23
|
+
layout_name = choose_from_options(multi=False, options=options, prompt="Choose a layout configuration:", fzf=True, msg="Choose one option")
|
|
24
24
|
print(f"Selected layout: {layout_name}")
|
|
25
25
|
layout_chosen = next((layout for layout in layout_file["layouts"] if layout["layoutName"] == layout_name), None)
|
|
26
26
|
if layout_chosen is None:
|
|
@@ -59,7 +59,7 @@ def handle_layout_args(args: "FireJobArgs") -> None:
|
|
|
59
59
|
print(f"🔍 Searching recursively for Python, PowerShell and Shell scripts in directory `{path_obj}`")
|
|
60
60
|
files = search_for_files_of_interest(path_obj)
|
|
61
61
|
print(f"🔍 Got #{len(files)} results.")
|
|
62
|
-
choice_file =
|
|
62
|
+
choice_file = choose_from_options(multi=False, options=files, fzf=True, msg="Choose one option")
|
|
63
63
|
choice_file = PathExtended(choice_file)
|
|
64
64
|
else:
|
|
65
65
|
choice_file = path_obj
|
|
@@ -8,9 +8,9 @@ Currently, the only way to work around this is to predifine the host in ~/.ssh/c
|
|
|
8
8
|
|
|
9
9
|
import argparse
|
|
10
10
|
from machineconfig.utils.ssh import SSH
|
|
11
|
-
from machineconfig.utils.
|
|
11
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
12
12
|
from machineconfig.scripts.python.helpers.helpers2 import ES
|
|
13
|
-
from machineconfig.utils.
|
|
13
|
+
from machineconfig.utils.accessories import pprint
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def main():
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
from machineconfig.utils.
|
|
2
|
+
from machineconfig.utils.io import read_ini, read_json
|
|
3
|
+
from machineconfig.utils.accessories import pprint
|
|
3
4
|
from typing import Optional
|
|
4
5
|
import os
|
|
5
6
|
from machineconfig.utils.source_of_truth import DEFAULTS_PATH
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from machineconfig.scripts.python.helpers.cloud_helpers import Args, ArgsDefaults, absolute, find_cloud_config, get_secure_share_cloud_config
|
|
2
|
+
from machineconfig.utils.io import read_ini
|
|
2
3
|
from machineconfig.utils.source_of_truth import DEFAULTS_PATH
|
|
3
|
-
from machineconfig.utils.
|
|
4
|
+
from machineconfig.utils.accessories import pprint
|
|
4
5
|
from typing import Optional
|
|
5
6
|
from rich.console import Console
|
|
6
7
|
from rich.panel import Panel
|
|
@@ -103,7 +104,7 @@ def parse_cloud_source_target(args: Args, source: str, target: str) -> tuple[str
|
|
|
103
104
|
if len(source_parts) > 1 and source_parts[1] == ES: # the source path is to be inferred from target.
|
|
104
105
|
assert ES not in target, f"You can't use expand symbol `{ES}` in both source and target. Cyclical inference dependency arised."
|
|
105
106
|
target_obj = absolute(target)
|
|
106
|
-
from machineconfig.utils.
|
|
107
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
107
108
|
|
|
108
109
|
remote_path = PathExtended(target_obj).get_remote_path(os_specific=os_specific, root=root, rel2home=rel2home, strict=False)
|
|
109
110
|
source = f"{cloud}:{remote_path.as_posix()}"
|
|
@@ -123,7 +124,7 @@ def parse_cloud_source_target(args: Args, source: str, target: str) -> tuple[str
|
|
|
123
124
|
if len(target_parts) > 1 and target_parts[1] == ES: # the target path is to be inferred from source.
|
|
124
125
|
assert ES not in source, "You can't use $ in both source and target. Cyclical inference dependency arised."
|
|
125
126
|
source_obj = absolute(source)
|
|
126
|
-
from machineconfig.utils.
|
|
127
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
127
128
|
|
|
128
129
|
remote_path = PathExtended(source_obj).get_remote_path(os_specific=os_specific, root=root, rel2home=rel2home, strict=False)
|
|
129
130
|
target = f"{cloud}:{remote_path.as_posix()}"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from machineconfig.utils.
|
|
1
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
2
2
|
from machineconfig.utils.terminal import Terminal
|
|
3
3
|
from machineconfig.scripts.python.get_zellij_cmd import get_zellij_cmd
|
|
4
4
|
from machineconfig.utils.source_of_truth import CONFIG_PATH, DEFAULTS_PATH
|
|
5
|
-
from machineconfig.utils.
|
|
5
|
+
from machineconfig.utils.io import read_ini
|
|
6
6
|
from machineconfig.utils.code import write_shell_script_to_file
|
|
7
7
|
import platform
|
|
8
8
|
from rich.console import Console
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""NFS mounting script"""
|
|
2
2
|
|
|
3
|
-
from machineconfig.utils.
|
|
3
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
4
4
|
from machineconfig.utils.ssh import SSH
|
|
5
5
|
from machineconfig.utils.terminal import Terminal
|
|
6
|
-
from machineconfig.utils.options import
|
|
6
|
+
from machineconfig.utils.options import choose_from_options, choose_ssh_host
|
|
7
7
|
|
|
8
8
|
import platform
|
|
9
9
|
|
|
@@ -20,7 +20,7 @@ def main():
|
|
|
20
20
|
assert isinstance(tmp, str)
|
|
21
21
|
ssh = SSH(tmp)
|
|
22
22
|
default = f"{ssh.hostname}:{ssh.run('echo $HOME').op}/data/share_nfs"
|
|
23
|
-
share_info =
|
|
23
|
+
share_info = choose_from_options(msg="📂 Choose a share path:", options=[f"{ssh.hostname}:{item.split(' ')[0]}" for item in ssh.run("cat /etc/exports").op.split("\n") if not item.startswith("#")] + [default], default=default, multi=False)
|
|
24
24
|
assert isinstance(share_info, str), f"❌ share_info must be a string. Got {type(share_info)}"
|
|
25
25
|
|
|
26
26
|
remote_server = share_info.split(":")[0]
|
|
@@ -38,7 +38,7 @@ def main():
|
|
|
38
38
|
mount_path_3 = mount_path_2
|
|
39
39
|
|
|
40
40
|
print("🔧 Preparing mount paths...")
|
|
41
|
-
local_mount_point =
|
|
41
|
+
local_mount_point = choose_from_options(msg="📂 Choose mount path OR input custom one:", options=[mount_path_1, mount_path_2, mount_path_3], default=mount_path_2, custom_input=True, multi=False)
|
|
42
42
|
assert isinstance(local_mount_point, PathExtended), f"❌ local_mount_point must be a pathlib.Path. Got {type(local_mount_point)}"
|
|
43
43
|
local_mount_point = PathExtended(local_mount_point).expanduser()
|
|
44
44
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from platform import system
|
|
4
4
|
from machineconfig.utils.ssh import SSH
|
|
5
5
|
from machineconfig.utils.terminal import Terminal
|
|
6
|
-
from machineconfig.utils.
|
|
6
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
7
7
|
|
|
8
8
|
from machineconfig.utils.options import choose_ssh_host
|
|
9
9
|
|
|
@@ -5,11 +5,13 @@ in the event that username@github.com is not mentioned in the remote url.
|
|
|
5
5
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
from machineconfig.utils.io import read_ini
|
|
8
9
|
from machineconfig.utils.source_of_truth import CONFIG_PATH, DEFAULTS_PATH
|
|
9
|
-
from machineconfig.utils.
|
|
10
|
-
from machineconfig.utils.
|
|
10
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
11
|
+
from machineconfig.utils.accessories import randstr
|
|
11
12
|
from machineconfig.scripts.python.repos_helper_update import update_repository
|
|
12
13
|
from machineconfig.scripts.python.repos_helper_record import main as record_repos
|
|
14
|
+
from machineconfig.scripts.python.repos_helper_clone import clone_repos
|
|
13
15
|
|
|
14
16
|
import argparse
|
|
15
17
|
from enum import Enum
|
|
@@ -119,7 +121,7 @@ def main():
|
|
|
119
121
|
elif args.clone or args.checkout or args.checkout_to_branch:
|
|
120
122
|
print("\n📥 Cloning or checking out repositories...")
|
|
121
123
|
print(">>>>>>>>> Cloning Repos")
|
|
122
|
-
if not repos_root.exists() or repos_root.name != "repos.json":
|
|
124
|
+
if not repos_root.exists() or repos_root.name != "repos.json":
|
|
123
125
|
repos_root = PathExtended(CONFIG_PATH).joinpath("repos").joinpath(repos_root.rel2home()).joinpath("repos.json")
|
|
124
126
|
if not repos_root.exists():
|
|
125
127
|
if args.cloud is None:
|
|
@@ -130,6 +132,7 @@ def main():
|
|
|
130
132
|
assert cloud is not None, f"Path {repos_root} does not exist and cloud was not passed. You can't clone without one of them."
|
|
131
133
|
repos_root.from_cloud(cloud=cloud, rel2home=True)
|
|
132
134
|
assert (repos_root.exists() and repos_root.name == "repos.json") or args.cloud is not None, f"Path {repos_root} does not exist and cloud was not passed. You can't clone without one of them."
|
|
135
|
+
clone_repos(spec_path=repos_root, preferred_remote=None, checkout_branch_flag=args.checkout_to_branch, checkout_commit_flag=args.checkout)
|
|
133
136
|
|
|
134
137
|
elif args.all or args.commit or args.pull or args.push:
|
|
135
138
|
print(f"\n🔄 Performing Git actions on repositories @ `{repos_root}`...")
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Literal, Optional, cast
|
|
4
|
+
|
|
5
|
+
from git import Repo as GitRepo
|
|
6
|
+
from git.exc import GitCommandError
|
|
7
|
+
from rich import print as pprint
|
|
8
|
+
from rich.progress import BarColumn, MofNCompleteColumn, Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
|
|
9
|
+
|
|
10
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
11
|
+
from machineconfig.utils.schemas.repos.repos_types import RepoRecordDict, RepoRecordFile, RepoRemote
|
|
12
|
+
from machineconfig.utils.io import read_json
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
CloneStatus = Literal["cloned", "skipped", "failed"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def choose_remote(remotes: list[RepoRemote], preferred_remote: Optional[str]) -> Optional[RepoRemote]:
|
|
19
|
+
if preferred_remote is not None:
|
|
20
|
+
for remote in remotes:
|
|
21
|
+
if remote["name"] == preferred_remote:
|
|
22
|
+
return remote
|
|
23
|
+
for remote in remotes:
|
|
24
|
+
if remote["name"] == "origin":
|
|
25
|
+
return remote
|
|
26
|
+
return remotes[0] if len(remotes) > 0 else None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def ensure_destination(parent_dir: str, name: str) -> PathExtended:
|
|
30
|
+
parent_path = PathExtended(parent_dir).expanduser().absolute()
|
|
31
|
+
parent_path.mkdir(parents=True, exist_ok=True)
|
|
32
|
+
return parent_path.joinpath(name)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def checkout_branch(repo: GitRepo, branch: str) -> bool:
|
|
36
|
+
if branch == "DETACHED":
|
|
37
|
+
return False
|
|
38
|
+
current_branch = repo.active_branch.name if not repo.head.is_detached else None
|
|
39
|
+
if current_branch == branch:
|
|
40
|
+
return False
|
|
41
|
+
repo.git.checkout(branch)
|
|
42
|
+
return True
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def checkout_commit(repo: GitRepo, commit: str) -> bool:
|
|
46
|
+
if commit in {"", "UNKNOWN"}:
|
|
47
|
+
return False
|
|
48
|
+
current_commit = repo.head.commit.hexsha
|
|
49
|
+
if current_commit == commit:
|
|
50
|
+
return False
|
|
51
|
+
repo.git.checkout(commit)
|
|
52
|
+
return True
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def clone_single_repo(repo_spec: RepoRecordDict, preferred_remote: Optional[str], checkout_branch_flag: bool, checkout_commit_flag: bool) -> tuple[CloneStatus, str]:
|
|
56
|
+
destination = ensure_destination(parent_dir=repo_spec["parentDir"], name=repo_spec["name"])
|
|
57
|
+
repo_path = destination.joinpath(".git")
|
|
58
|
+
remotes = repo_spec["remotes"]
|
|
59
|
+
if len(remotes) == 0:
|
|
60
|
+
return ("failed", f"No remotes configured for {destination}")
|
|
61
|
+
remote = choose_remote(remotes=remotes, preferred_remote=preferred_remote)
|
|
62
|
+
if remote is None:
|
|
63
|
+
return ("failed", f"No usable remote for {destination}")
|
|
64
|
+
repo = None
|
|
65
|
+
status: CloneStatus
|
|
66
|
+
message: str
|
|
67
|
+
if destination.exists() and repo_path.exists():
|
|
68
|
+
status = "skipped"
|
|
69
|
+
repo = GitRepo(str(destination))
|
|
70
|
+
message = f"Skipped cloning for {destination}; existing repository reused"
|
|
71
|
+
elif destination.exists() and not repo_path.exists():
|
|
72
|
+
return ("failed", f"Destination exists but is not a git repository: {destination}")
|
|
73
|
+
else:
|
|
74
|
+
try:
|
|
75
|
+
pprint(f"📥 Cloning {repo_spec['name']} from {remote['url']}")
|
|
76
|
+
repo = GitRepo.clone_from(url=remote["url"], to_path=str(destination))
|
|
77
|
+
status = "cloned"
|
|
78
|
+
message = f"Cloned {destination}"
|
|
79
|
+
except Exception as err: # noqa: BLE001
|
|
80
|
+
return ("failed", f"Clone failed for {destination}: {err}")
|
|
81
|
+
assert repo is not None
|
|
82
|
+
checkout_summary: list[str] = []
|
|
83
|
+
try:
|
|
84
|
+
if checkout_branch_flag:
|
|
85
|
+
if checkout_branch(repo=repo, branch=repo_spec["version"]["branch"]):
|
|
86
|
+
checkout_summary.append(f"branch {repo_spec['version']['branch']}")
|
|
87
|
+
if checkout_commit_flag:
|
|
88
|
+
if checkout_commit(repo=repo, commit=repo_spec["version"]["commit"]):
|
|
89
|
+
checkout_summary.append(f"commit {repo_spec['version']['commit'][:8]}")
|
|
90
|
+
except GitCommandError as err:
|
|
91
|
+
return ("failed", f"Checkout failed for {destination}: {err}")
|
|
92
|
+
if len(checkout_summary) > 0:
|
|
93
|
+
message = f"{message} | Checked out {' & '.join(checkout_summary)}"
|
|
94
|
+
return (status, message)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def clone_repos(spec_path: PathExtended, preferred_remote: Optional[str], checkout_branch_flag: bool, checkout_commit_flag: bool) -> list[tuple[CloneStatus, str]]:
|
|
98
|
+
data = cast(RepoRecordFile, read_json(path=spec_path))
|
|
99
|
+
repos = data["repos"]
|
|
100
|
+
results: list[tuple[CloneStatus, str]] = []
|
|
101
|
+
with Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), BarColumn(), MofNCompleteColumn(), TimeElapsedColumn()) as progress:
|
|
102
|
+
task_id = progress.add_task("Processing repositories...", total=len(repos))
|
|
103
|
+
for repo_spec in repos:
|
|
104
|
+
progress.update(task_id, description=f"Processing {repo_spec['name']}")
|
|
105
|
+
try:
|
|
106
|
+
result = clone_single_repo(repo_spec=repo_spec, preferred_remote=preferred_remote, checkout_branch_flag=checkout_branch_flag, checkout_commit_flag=checkout_commit_flag)
|
|
107
|
+
except Exception as err: # noqa: BLE001
|
|
108
|
+
result = ("failed", f"Unexpected error for {repo_spec['name']}: {err}")
|
|
109
|
+
results.append(result)
|
|
110
|
+
if result[0] == "failed":
|
|
111
|
+
pprint(f"❌ {result[1]}")
|
|
112
|
+
elif result[0] == "cloned":
|
|
113
|
+
pprint(f"✅ {result[1]}")
|
|
114
|
+
else:
|
|
115
|
+
pprint(f"⏭️ {result[1]}")
|
|
116
|
+
progress.update(task_id, advance=1)
|
|
117
|
+
success_count = len([status for status, _ in results if status == "cloned"])
|
|
118
|
+
skip_count = len([status for status, _ in results if status == "skipped"])
|
|
119
|
+
fail_count = len([status for status, _ in results if status == "failed"])
|
|
120
|
+
pprint(f"✅ Cloned: {success_count} | ⏭️ Skipped: {skip_count} | ❌ Failed: {fail_count}")
|
|
121
|
+
return results
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
from machineconfig.utils.
|
|
1
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
2
2
|
from machineconfig.utils.schemas.repos.repos_types import GitVersionInfo, RepoRecordDict, RepoRemote
|
|
3
3
|
|
|
4
4
|
from machineconfig.utils.schemas.repos.repos_types import RepoRecordFile
|
|
5
5
|
from machineconfig.utils.source_of_truth import CONFIG_PATH
|
|
6
|
-
from machineconfig.utils.
|
|
6
|
+
from machineconfig.utils.io import save_json
|
|
7
7
|
|
|
8
8
|
from typing import Optional
|
|
9
9
|
|
|
@@ -4,7 +4,7 @@ slidev
|
|
|
4
4
|
|
|
5
5
|
from machineconfig.utils.source_of_truth import CONFIG_PATH
|
|
6
6
|
from machineconfig.utils.code import print_code
|
|
7
|
-
from machineconfig.utils.
|
|
7
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
8
8
|
from machineconfig.utils.terminal import Terminal
|
|
9
9
|
import subprocess
|
|
10
10
|
import platform
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Script to start terminals on windows and wsl"""
|
|
2
2
|
|
|
3
|
-
from machineconfig.utils.options import
|
|
3
|
+
from machineconfig.utils.options import choose_from_options, get_ssh_hosts
|
|
4
4
|
import platform
|
|
5
5
|
from itertools import cycle
|
|
6
6
|
from typing import Literal
|
|
@@ -98,7 +98,7 @@ def main():
|
|
|
98
98
|
else:
|
|
99
99
|
if args.hosts is None:
|
|
100
100
|
print("🌐 No hosts provided. Displaying options...")
|
|
101
|
-
hosts =
|
|
101
|
+
hosts = choose_from_options(msg="Select hosts:", options=get_ssh_hosts() + [THIS_MACHINE], multi=True, fzf=True)
|
|
102
102
|
else:
|
|
103
103
|
print("🌐 Using provided hosts:", args.hosts)
|
|
104
104
|
hosts = args.hosts
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
# @register_line_magic("codei") # type: ignore
|
|
27
27
|
# def print_code_interactive(_):
|
|
28
28
|
# res = get_names()
|
|
29
|
-
# from machineconfig.utils.utils import
|
|
30
|
-
# choice =
|
|
29
|
+
# from machineconfig.utils.utils import choose_from_options
|
|
30
|
+
# choice = choose_from_options(multi=False, options=res["<class 'function'>"], msg="Choose a type to inspect", fzf=True)
|
|
31
31
|
# obj = eval(choice, globals(), locals()) # type: ignore # pylint: disable=eval-used
|
|
32
32
|
# from rich.syntax import Syntax
|
|
33
33
|
# import inspect
|
|
@@ -4,7 +4,7 @@ https://glitchbone.github.io/vscode-base16-term/#/3024
|
|
|
4
4
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from machineconfig.utils.
|
|
7
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
8
8
|
from machineconfig.utils.source_of_truth import LIBRARY_ROOT
|
|
9
9
|
from machineconfig.utils.installer_utils.installer_class import Installer
|
|
10
10
|
import subprocess
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""Set Windows Terminal Settings"""
|
|
2
2
|
|
|
3
|
-
from machineconfig.utils.
|
|
4
|
-
from machineconfig.utils.
|
|
5
|
-
from machineconfig.utils.
|
|
3
|
+
from machineconfig.utils.accessories import randstr
|
|
4
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
5
|
+
from machineconfig.utils.io import read_json, save_json
|
|
6
6
|
import platform
|
|
7
7
|
|
|
8
8
|
# from uuid import uuid4
|
|
@@ -32,35 +32,6 @@ def split[T](iterable: list[T], every: int = 1, to: Optional[int] = None) -> lis
|
|
|
32
32
|
return list(res)
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
def read_ini(path: "Path", encoding: Optional[str] = None):
|
|
36
|
-
if not Path(path).exists() or Path(path).is_dir():
|
|
37
|
-
raise FileNotFoundError(f"File not found or is a directory: {path}")
|
|
38
|
-
import configparser
|
|
39
|
-
|
|
40
|
-
res = configparser.ConfigParser()
|
|
41
|
-
res.read(filenames=[str(path)], encoding=encoding)
|
|
42
|
-
return res
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def read_json(path: "Path", r: bool = False, **kwargs: Any) -> Any: # return could be list or dict etc
|
|
46
|
-
import json
|
|
47
|
-
|
|
48
|
-
try:
|
|
49
|
-
mydict = json.loads(Path(path).read_text(encoding="utf-8"), **kwargs)
|
|
50
|
-
except Exception:
|
|
51
|
-
import pyjson5
|
|
52
|
-
|
|
53
|
-
mydict = pyjson5.loads(Path(path).read_text(encoding="utf-8"), **kwargs) # file has C-style comments.
|
|
54
|
-
_ = r
|
|
55
|
-
return mydict
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def read_toml(path: "Path"):
|
|
59
|
-
import tomli
|
|
60
|
-
|
|
61
|
-
return tomli.loads(path.read_text(encoding="utf-8"))
|
|
62
|
-
|
|
63
|
-
|
|
64
35
|
def pprint(obj: dict[Any, Any], title: str) -> None:
|
|
65
36
|
from rich import inspect
|
|
66
37
|
|
|
@@ -86,3 +57,16 @@ def human_friendly_dict(d: dict[str, Any]) -> dict[str, Any]:
|
|
|
86
57
|
else:
|
|
87
58
|
result[k] = v
|
|
88
59
|
return result
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_repo_root(path: Path) -> Optional[Path]:
|
|
63
|
+
from git import Repo, InvalidGitRepositoryError
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
repo = Repo(str(path), search_parent_directories=True)
|
|
67
|
+
root = repo.working_tree_dir
|
|
68
|
+
if root is not None:
|
|
69
|
+
return Path(root)
|
|
70
|
+
except InvalidGitRepositoryError:
|
|
71
|
+
pass
|
|
72
|
+
return None
|
machineconfig/utils/code.py
CHANGED
|
@@ -5,9 +5,9 @@ from rich.console import Console
|
|
|
5
5
|
from rich.panel import Panel
|
|
6
6
|
from rich.syntax import Syntax
|
|
7
7
|
|
|
8
|
-
from machineconfig.utils.
|
|
8
|
+
from machineconfig.utils.accessories import randstr
|
|
9
9
|
from machineconfig.utils.ve import get_ve_activate_line
|
|
10
|
-
from machineconfig.utils.
|
|
10
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def get_shell_script_executing_python_file(python_file: str, func: Optional[str], ve_path: str, strict_execution: bool = True):
|
machineconfig/utils/installer.py
CHANGED
|
@@ -6,9 +6,9 @@ from machineconfig.utils.schemas.installer.installer_types import APP_INSTALLER_
|
|
|
6
6
|
from rich.console import Console
|
|
7
7
|
from rich.panel import Panel # Added import
|
|
8
8
|
|
|
9
|
-
from machineconfig.utils.
|
|
9
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
10
10
|
from machineconfig.utils.source_of_truth import INSTALL_VERSION_ROOT
|
|
11
|
-
from machineconfig.utils.
|
|
11
|
+
from machineconfig.utils.io import read_json
|
|
12
12
|
|
|
13
13
|
from typing import Any
|
|
14
14
|
import platform
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from machineconfig.utils.
|
|
1
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
2
2
|
from machineconfig.utils.source_of_truth import WINDOWS_INSTALL_PATH, LINUX_INSTALL_PATH
|
|
3
3
|
from typing import Optional
|
|
4
4
|
import subprocess
|