machineconfig 5.20__py3-none-any.whl → 5.22__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/sessions_managers/zellij_local.py +1 -3
- machineconfig/jobs/installer/custom_dev/brave.py +0 -6
- machineconfig/jobs/installer/package_groups.py +12 -12
- machineconfig/profile/shell.py +1 -1
- machineconfig/scripts/python/cloud_repo_sync.py +21 -22
- machineconfig/scripts/python/croshell.py +2 -4
- machineconfig/scripts/python/devops.py +18 -9
- machineconfig/scripts/python/devops_status.py +521 -0
- machineconfig/scripts/python/devops_update_repos.py +1 -3
- machineconfig/scripts/python/fire_jobs.py +15 -50
- machineconfig/scripts/python/fire_jobs_args_helper.py +4 -1
- machineconfig/scripts/python/fire_jobs_route_helper.py +46 -0
- machineconfig/scripts/python/helpers/repo_sync_helpers.py +0 -40
- machineconfig/scripts/python/onetimeshare.py +0 -1
- machineconfig/scripts/python/sessions.py +7 -10
- machineconfig/scripts/python/sessions_multiprocess.py +56 -0
- machineconfig/setup_linux/repos.sh +1 -29
- machineconfig/setup_windows/repos.ps1 +0 -12
- machineconfig/utils/files/read.py +4 -6
- machineconfig/utils/notifications.py +1 -1
- machineconfig/utils/ssh.py +2 -13
- {machineconfig-5.20.dist-info → machineconfig-5.22.dist-info}/METADATA +1 -1
- {machineconfig-5.20.dist-info → machineconfig-5.22.dist-info}/RECORD +26 -24
- {machineconfig-5.20.dist-info → machineconfig-5.22.dist-info}/WHEEL +0 -0
- {machineconfig-5.20.dist-info → machineconfig-5.22.dist-info}/entry_points.txt +0 -0
- {machineconfig-5.20.dist-info → machineconfig-5.22.dist-info}/top_level.txt +0 -0
|
@@ -7,17 +7,13 @@ fire
|
|
|
7
7
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
from machineconfig.scripts.python.fire_jobs_route_helper import get_command_streamlit
|
|
11
|
-
from machineconfig.scripts.python.helpers.helpers4 import search_for_files_of_interest
|
|
12
|
-
from machineconfig.scripts.python.helpers.helpers4 import parse_pyfile
|
|
13
|
-
from machineconfig.scripts.python.helpers.helpers4 import get_import_module_code
|
|
14
10
|
from machineconfig.utils.ve import get_ve_activate_line, get_ve_path_and_ipython_profile
|
|
15
11
|
from machineconfig.utils.options import choose_from_options
|
|
16
12
|
from machineconfig.utils.path_helper import match_file_name, sanitize_path
|
|
17
|
-
|
|
18
13
|
from machineconfig.utils.path_extended import PathExtended
|
|
19
14
|
from machineconfig.utils.accessories import get_repo_root, randstr
|
|
20
15
|
from machineconfig.scripts.python.fire_jobs_args_helper import FireJobArgs, extract_kwargs, parse_fire_args_from_context
|
|
16
|
+
|
|
21
17
|
import platform
|
|
22
18
|
from typing import Optional, Annotated
|
|
23
19
|
from pathlib import Path
|
|
@@ -30,6 +26,7 @@ def route(args: FireJobArgs, fire_args: str = "") -> None:
|
|
|
30
26
|
suffixes = {".py", ".sh", ".ps1"}
|
|
31
27
|
choice_file = match_file_name(sub_string=args.path, search_root=PathExtended.cwd(), suffixes=suffixes)
|
|
32
28
|
elif path_obj.is_dir():
|
|
29
|
+
from machineconfig.scripts.python.helpers.helpers4 import search_for_files_of_interest
|
|
33
30
|
print(f"🔍 Searching recursively for Python, PowerShell and Shell scripts in directory `{path_obj}`")
|
|
34
31
|
files = search_for_files_of_interest(path_obj)
|
|
35
32
|
print(f"🔍 Got #{len(files)} results.")
|
|
@@ -37,12 +34,16 @@ def route(args: FireJobArgs, fire_args: str = "") -> None:
|
|
|
37
34
|
choice_file = PathExtended(choice_file)
|
|
38
35
|
else:
|
|
39
36
|
choice_file = path_obj
|
|
37
|
+
|
|
38
|
+
|
|
40
39
|
repo_root = get_repo_root(Path(choice_file))
|
|
41
40
|
print(f"💾 Selected file: {choice_file}.\nRepo root: {repo_root}")
|
|
42
41
|
ve_root_from_file, ipy_profile = get_ve_path_and_ipython_profile(choice_file)
|
|
43
42
|
if ipy_profile is None:
|
|
44
43
|
ipy_profile = "default"
|
|
45
44
|
|
|
45
|
+
|
|
46
|
+
# ========================= preparing kwargs_dict
|
|
46
47
|
if choice_file.suffix == ".py":
|
|
47
48
|
kwargs_dict = extract_kwargs(args) # This now returns empty dict, but kept for compatibility
|
|
48
49
|
activate_ve_line = get_ve_activate_line(ve_root=args.ve or ve_root_from_file or "$HOME/code/machineconfig/.venv")
|
|
@@ -50,41 +51,17 @@ def route(args: FireJobArgs, fire_args: str = "") -> None:
|
|
|
50
51
|
activate_ve_line = ""
|
|
51
52
|
kwargs_dict = {}
|
|
52
53
|
|
|
54
|
+
|
|
53
55
|
# ========================= choosing function to run
|
|
54
56
|
choice_function: Optional[str] = None # Initialize to avoid unbound variable
|
|
55
|
-
if args.choose_function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
choice_function_tmp = choose_from_options(msg="Choose a function to run", options=options, fzf=True, multi=False)
|
|
59
|
-
assert isinstance(choice_function_tmp, str), f"choice_function must be a string. Got {type(choice_function_tmp)}"
|
|
60
|
-
choice_index = options.index(choice_function_tmp)
|
|
61
|
-
choice_function = choice_function_tmp.split(" -- ")[0]
|
|
62
|
-
choice_function_args = func_args[choice_index]
|
|
63
|
-
|
|
64
|
-
if choice_function == "RUN AS MAIN":
|
|
65
|
-
choice_function = None
|
|
66
|
-
if len(choice_function_args) > 0 and len(kwargs_dict) == 0:
|
|
67
|
-
for item in choice_function_args:
|
|
68
|
-
kwargs_dict[item.name] = input(f"Please enter a value for argument `{item.name}` (type = {item.type}) (default = {item.default}) : ") or item.default
|
|
69
|
-
elif choice_file.suffix == ".sh": # in this case, we choos lines.
|
|
70
|
-
options = []
|
|
71
|
-
for line in choice_file.read_text(encoding="utf-8").splitlines():
|
|
72
|
-
if line.startswith("#"):
|
|
73
|
-
continue
|
|
74
|
-
if line == "":
|
|
75
|
-
continue
|
|
76
|
-
if line.startswith("echo"):
|
|
77
|
-
continue
|
|
78
|
-
options.append(line)
|
|
79
|
-
chosen_lines = choose_from_options(msg="Choose a line to run", options=options, fzf=True, multi=True)
|
|
80
|
-
choice_file = PathExtended.tmpfile(suffix=".sh")
|
|
81
|
-
choice_file.parent.mkdir(parents=True, exist_ok=True)
|
|
82
|
-
choice_file.write_text("\n".join(chosen_lines), encoding="utf-8")
|
|
83
|
-
choice_function = None
|
|
57
|
+
if args.choose_function:
|
|
58
|
+
from machineconfig.scripts.python.fire_jobs_route_helper import choose_function_or_lines
|
|
59
|
+
choice_function, choice_file, kwargs_dict = choose_function_or_lines(choice_file, kwargs_dict)
|
|
84
60
|
else:
|
|
85
61
|
choice_function = args.function
|
|
86
62
|
|
|
87
63
|
if choice_file.suffix == ".py":
|
|
64
|
+
from machineconfig.scripts.python.fire_jobs_route_helper import get_command_streamlit
|
|
88
65
|
if args.streamlit: exe = get_command_streamlit(choice_file, args.environment, repo_root)
|
|
89
66
|
elif args.interactive is False: exe = "python"
|
|
90
67
|
elif args.jupyter: exe = "jupyter-lab"
|
|
@@ -95,6 +72,7 @@ def route(args: FireJobArgs, fire_args: str = "") -> None:
|
|
|
95
72
|
|
|
96
73
|
if args.module or (args.debug and args.choose_function): # because debugging tools do not support choosing functions and don't interplay with fire module. So the only way to have debugging and choose function options is to import the file as a module into a new script and run the function of interest there and debug the new script.
|
|
97
74
|
assert choice_file.suffix == ".py", f"File must be a python file to be imported as a module. Got {choice_file}"
|
|
75
|
+
from machineconfig.scripts.python.helpers.helpers4 import get_import_module_code
|
|
98
76
|
import_line = get_import_module_code(str(choice_file))
|
|
99
77
|
if repo_root is not None:
|
|
100
78
|
repo_root_add = f"""sys.path.append(r'{repo_root}')"""
|
|
@@ -160,11 +138,9 @@ except ImportError as _ex:
|
|
|
160
138
|
elif args.cmd:
|
|
161
139
|
command = rf""" cd /d {choice_file.parent} & {exe} {choice_file.name} """
|
|
162
140
|
else:
|
|
163
|
-
if choice_file.suffix == "":
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
# command = f"cd {choice_file.parent}\n{exe} {choice_file.name}\ncd {PathExtended.cwd()}"
|
|
167
|
-
command = f"{exe} {choice_file} "
|
|
141
|
+
if choice_file.suffix == "": command = f"{exe} {choice_file} {fire_args}"
|
|
142
|
+
else: command = f"{exe} {choice_file} "
|
|
143
|
+
|
|
168
144
|
if not args.cmd: command = f"{activate_ve_line}\n{command}"
|
|
169
145
|
else:
|
|
170
146
|
new_line = "\n"
|
|
@@ -176,14 +152,6 @@ python -m machineconfig.cluster.templates.cli_click --file {choice_file} """
|
|
|
176
152
|
if choice_function is not None:
|
|
177
153
|
command += f"--function {choice_function} "
|
|
178
154
|
|
|
179
|
-
if args.Nprocess > 1:
|
|
180
|
-
from machineconfig.cluster.sessions_managers.zellij_local import run_zellij_layout
|
|
181
|
-
from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
|
|
182
|
-
layout: LayoutConfig = {"layoutName": "fireNprocess", "layoutTabs": []}
|
|
183
|
-
for an_arg in range(args.Nprocess):
|
|
184
|
-
layout["layoutTabs"].append({"tabName": f"tab{an_arg}", "startDir": str(PathExtended.cwd()), "command": f"uv run -m fire {choice_file} {choice_function} --idx={an_arg} --idx_max={args.Nprocess}"})
|
|
185
|
-
run_zellij_layout(layout_config=layout)
|
|
186
|
-
return None
|
|
187
155
|
if args.optimized:
|
|
188
156
|
command = command.replace("python ", "python -OO ")
|
|
189
157
|
from rich.panel import Panel
|
|
@@ -245,7 +213,6 @@ def main(
|
|
|
245
213
|
PathExport: Annotated[bool, typer.Option("--PathExport", "-P", help="Augment the PYTHONPATH with repo root")] = False,
|
|
246
214
|
git_pull: Annotated[bool, typer.Option("--git_pull", "-g", help="Start by pulling the git repo")] = False,
|
|
247
215
|
optimized: Annotated[bool, typer.Option("--optimized", "-O", help="Run the optimized version of the function")] = False,
|
|
248
|
-
Nprocess: Annotated[int, typer.Option("--Nprocess", "-p", help="Number of processes to use")] = 1,
|
|
249
216
|
zellij_tab: Annotated[Optional[str], typer.Option("--zellij_tab", "-z", help="Open in a new zellij tab")] = None,
|
|
250
217
|
watch: Annotated[bool, typer.Option("--watch", "-w", help="Watch the file for changes")] = False,
|
|
251
218
|
) -> None:
|
|
@@ -273,7 +240,6 @@ def main(
|
|
|
273
240
|
PathExport=PathExport,
|
|
274
241
|
git_pull=git_pull,
|
|
275
242
|
optimized=optimized,
|
|
276
|
-
Nprocess=Nprocess,
|
|
277
243
|
zellij_tab=zellij_tab,
|
|
278
244
|
watch=watch,
|
|
279
245
|
)
|
|
@@ -303,5 +269,4 @@ def main_from_parser():
|
|
|
303
269
|
|
|
304
270
|
|
|
305
271
|
if __name__ == "__main__":
|
|
306
|
-
# options, func_args = parse_pyfile(file_path="C:/Users/aalsaf01/code/machineconfig/myresources/crocodile/core.py")
|
|
307
272
|
main_from_parser()
|
|
@@ -24,7 +24,6 @@ class FireJobArgs:
|
|
|
24
24
|
PathExport: bool = False
|
|
25
25
|
git_pull: bool = False
|
|
26
26
|
optimized: bool = False
|
|
27
|
-
Nprocess: int = 1
|
|
28
27
|
zellij_tab: Optional[str] = None
|
|
29
28
|
watch: bool = False
|
|
30
29
|
|
|
@@ -96,6 +95,10 @@ def _convert_value_type(value: str) -> object:
|
|
|
96
95
|
elif value.lower() in ('false', '0', 'no', 'off'):
|
|
97
96
|
return False
|
|
98
97
|
|
|
98
|
+
# Try to convert None
|
|
99
|
+
if value.lower() == 'none':
|
|
100
|
+
return None
|
|
101
|
+
|
|
99
102
|
# Try to parse as list (comma-separated values)
|
|
100
103
|
if ',' in value:
|
|
101
104
|
items = [_convert_value_type(item.strip()) for item in value.split(',')]
|
|
@@ -6,6 +6,52 @@ import tomllib
|
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from machineconfig.utils.accessories import randstr
|
|
8
8
|
from machineconfig.utils.path_extended import PathExtended
|
|
9
|
+
from machineconfig.utils.options import choose_from_options
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def choose_function_or_lines(choice_file: PathExtended, kwargs_dict: dict[str, object]) -> tuple[Optional[str], PathExtended, dict[str, object]]:
|
|
13
|
+
"""
|
|
14
|
+
Choose a function to run from a Python file or lines from a shell script.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
tuple: (choice_function, choice_file, kwargs_dict)
|
|
18
|
+
- choice_function: The selected function name or None
|
|
19
|
+
- choice_file: The file path (potentially modified for shell scripts)
|
|
20
|
+
- kwargs_dict: Updated kwargs dictionary with user-provided arguments
|
|
21
|
+
"""
|
|
22
|
+
choice_function: Optional[str] = None
|
|
23
|
+
|
|
24
|
+
if choice_file.suffix == ".py":
|
|
25
|
+
from machineconfig.scripts.python.helpers.helpers4 import parse_pyfile
|
|
26
|
+
options, func_args = parse_pyfile(file_path=str(choice_file))
|
|
27
|
+
choice_function_tmp = choose_from_options(msg="Choose a function to run", options=options, fzf=True, multi=False)
|
|
28
|
+
assert isinstance(choice_function_tmp, str), f"choice_function must be a string. Got {type(choice_function_tmp)}"
|
|
29
|
+
choice_index = options.index(choice_function_tmp)
|
|
30
|
+
choice_function = choice_function_tmp.split(" -- ")[0]
|
|
31
|
+
choice_function_args = func_args[choice_index]
|
|
32
|
+
|
|
33
|
+
if choice_function == "RUN AS MAIN":
|
|
34
|
+
choice_function = None
|
|
35
|
+
if len(choice_function_args) > 0 and len(kwargs_dict) == 0:
|
|
36
|
+
for item in choice_function_args:
|
|
37
|
+
kwargs_dict[item.name] = input(f"Please enter a value for argument `{item.name}` (type = {item.type}) (default = {item.default}) : ") or item.default
|
|
38
|
+
elif choice_file.suffix == ".sh":
|
|
39
|
+
options = []
|
|
40
|
+
for line in choice_file.read_text(encoding="utf-8").splitlines():
|
|
41
|
+
if line.startswith("#"):
|
|
42
|
+
continue
|
|
43
|
+
if line == "":
|
|
44
|
+
continue
|
|
45
|
+
if line.startswith("echo"):
|
|
46
|
+
continue
|
|
47
|
+
options.append(line)
|
|
48
|
+
chosen_lines = choose_from_options(msg="Choose a line to run", options=options, fzf=True, multi=True)
|
|
49
|
+
choice_file = PathExtended.tmpfile(suffix=".sh")
|
|
50
|
+
choice_file.parent.mkdir(parents=True, exist_ok=True)
|
|
51
|
+
choice_file.write_text("\n".join(chosen_lines), encoding="utf-8")
|
|
52
|
+
choice_function = None
|
|
53
|
+
|
|
54
|
+
return choice_function, choice_file, kwargs_dict
|
|
9
55
|
|
|
10
56
|
|
|
11
57
|
def get_command_streamlit(choice_file: Path, environment: str, repo_root: Optional[Path]) -> str:
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
from machineconfig.utils.path_extended import PathExtended
|
|
2
|
-
from machineconfig.utils.terminal import Response
|
|
3
2
|
from machineconfig.scripts.python.get_zellij_cmd import get_zellij_cmd
|
|
4
|
-
from machineconfig.utils.source_of_truth import CONFIG_PATH, DEFAULTS_PATH
|
|
5
|
-
from machineconfig.utils.io import read_ini
|
|
6
3
|
from machineconfig.utils.code import write_shell_script_to_file
|
|
7
4
|
import platform
|
|
8
|
-
import subprocess
|
|
9
5
|
from rich.console import Console
|
|
10
6
|
from rich.panel import Panel
|
|
11
7
|
|
|
@@ -60,42 +56,6 @@ def inspect_repos(repo_local_root: str, repo_remote_root: str):
|
|
|
60
56
|
raise NotImplementedError(f"Platform {platform.system()} not implemented.")
|
|
61
57
|
|
|
62
58
|
|
|
63
|
-
def fetch_dotfiles():
|
|
64
|
-
console.print(Panel("📁 Fetching Dotfiles", title="[bold blue]Dotfiles[/bold blue]", border_style="blue"))
|
|
65
|
-
|
|
66
|
-
cloud_resolved = read_ini(DEFAULTS_PATH)["general"]["rclone_config_name"]
|
|
67
|
-
console.print(Panel(f"⚠️ Using default cloud: `{cloud_resolved}` from {DEFAULTS_PATH}", width=150, border_style="yellow"))
|
|
68
|
-
|
|
69
|
-
dotfiles_local = PathExtended.home().joinpath("dotfiles")
|
|
70
|
-
CONFIG_PATH.joinpath("remote").mkdir(parents=True, exist_ok=True)
|
|
71
|
-
dotfiles_remote = PathExtended(CONFIG_PATH).joinpath("remote", dotfiles_local.rel2home())
|
|
72
|
-
remote_path = dotfiles_local.get_remote_path(rel2home=True, os_specific=False, root="myhome") + ".zip.enc"
|
|
73
|
-
|
|
74
|
-
console.print(Panel("📥 Downloading dotfiles from cloud...", width=150, border_style="blue"))
|
|
75
|
-
|
|
76
|
-
dotfiles_remote.from_cloud(remotepath=remote_path, cloud=cloud_resolved, unzip=True, decrypt=True, rel2home=True, os_specific=False, pwd=None)
|
|
77
|
-
|
|
78
|
-
console.print(Panel("🗑️ Removing old dotfiles and replacing with cloud version...", width=150, border_style="blue"))
|
|
79
|
-
|
|
80
|
-
dotfiles_local.delete(sure=True)
|
|
81
|
-
dotfiles_remote.move(folder=PathExtended.home())
|
|
82
|
-
script = f"""
|
|
83
|
-
# rm -rf {dotfiles_local}
|
|
84
|
-
# mv {dotfiles_remote} {dotfiles_local}
|
|
85
|
-
"""
|
|
86
|
-
if platform.system() == "Linux":
|
|
87
|
-
script += """
|
|
88
|
-
sudo chmod 600 $HOME/.ssh/*
|
|
89
|
-
sudo chmod 700 $HOME/.ssh
|
|
90
|
-
sudo chmod +x $HOME/dotfiles/scripts/linux -R
|
|
91
|
-
"""
|
|
92
|
-
shell_path = write_shell_script_to_file(shell_script=script)
|
|
93
|
-
completed = subprocess.run(f". {shell_path}", capture_output=True, check=False, text=True, shell=True)
|
|
94
|
-
Response.from_completed_process(completed).capture().print()
|
|
95
|
-
|
|
96
|
-
console.print(Panel("✅ Dotfiles successfully fetched and installed", title="[bold green]Dotfiles[/bold green]", border_style="green"))
|
|
97
|
-
|
|
98
|
-
|
|
99
59
|
def check_dotfiles_version_is_beyond(commit_dtm: str, update: bool) -> bool:
|
|
100
60
|
dotfiles_path = str(PathExtended.home().joinpath("dotfiles"))
|
|
101
61
|
from git import Repo
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from typing import Optional, Literal
|
|
4
4
|
import typer
|
|
5
|
-
|
|
5
|
+
from machineconfig.scripts.python.sessions_multiprocess import create_from_function
|
|
6
6
|
|
|
7
7
|
def balance_load(layout_path: Path = typer.Argument(..., help="Path to the layout.json file"),
|
|
8
8
|
max_thresh: int = typer.Option(..., help="Maximum tabs per layout"),
|
|
@@ -69,7 +69,7 @@ def find_layout_file(layout_path: str, ) -> Path:
|
|
|
69
69
|
return choice_file
|
|
70
70
|
|
|
71
71
|
|
|
72
|
-
def
|
|
72
|
+
def run(ctx: typer.Context,
|
|
73
73
|
layout_path: Optional[str] = typer.Argument(None, help="Path to the layout.json file"),
|
|
74
74
|
max_tabs: int = typer.Option(10, help="A Sanity checker that throws an error if any layout exceeds the maximum number of tabs to launch."),
|
|
75
75
|
max_layouts: int = typer.Option(10, help="A Sanity checker that throws an error if the total number of layouts exceeds this number."),
|
|
@@ -133,14 +133,11 @@ def launch(ctx: typer.Context,
|
|
|
133
133
|
|
|
134
134
|
|
|
135
135
|
def main_from_parser():
|
|
136
|
-
layouts_app = typer.Typer(help="Layouts management subcommands")
|
|
137
|
-
layouts_app.command("
|
|
138
|
-
layouts_app.command("
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
layouts_app(["--help"])
|
|
142
|
-
else:
|
|
143
|
-
layouts_app()
|
|
136
|
+
layouts_app = typer.Typer(help="Layouts management subcommands", no_args_is_help=True)
|
|
137
|
+
layouts_app.command("create-from-function", no_args_is_help=True)(create_from_function)
|
|
138
|
+
layouts_app.command("run", no_args_is_help=True)(run)
|
|
139
|
+
layouts_app.command("balance-load", no_args_is_help=True)(balance_load)
|
|
140
|
+
layouts_app()
|
|
144
141
|
|
|
145
142
|
|
|
146
143
|
if __name__ == "__main__":
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def create_from_function(
|
|
9
|
+
num_process: int = typer.Option(..., "--num-process", "-n", help="Number of parallel processes to run"),
|
|
10
|
+
path: str = typer.Option(".", "--path", "-p", help="Path to a Python or Shell script file or a directory containing such files"),
|
|
11
|
+
function: Optional[str] = typer.Option(None, "--function", "-f", help="Function to run from the Python file. If not provided, you will be prompted to choose."),
|
|
12
|
+
):
|
|
13
|
+
from machineconfig.utils.ve import get_ve_activate_line, get_ve_path_and_ipython_profile
|
|
14
|
+
from machineconfig.utils.options import choose_from_options
|
|
15
|
+
from machineconfig.utils.path_helper import match_file_name, sanitize_path
|
|
16
|
+
from machineconfig.utils.path_extended import PathExtended
|
|
17
|
+
from machineconfig.utils.accessories import get_repo_root
|
|
18
|
+
|
|
19
|
+
path_obj = sanitize_path(path)
|
|
20
|
+
if not path_obj.exists():
|
|
21
|
+
suffixes = {".py"}
|
|
22
|
+
choice_file = match_file_name(sub_string=path, search_root=PathExtended.cwd(), suffixes=suffixes)
|
|
23
|
+
elif path_obj.is_dir():
|
|
24
|
+
from machineconfig.scripts.python.helpers.helpers4 import search_for_files_of_interest
|
|
25
|
+
print(f"🔍 Searching recursively for Python, PowerShell and Shell scripts in directory `{path_obj}`")
|
|
26
|
+
files = search_for_files_of_interest(path_obj)
|
|
27
|
+
print(f"🔍 Got #{len(files)} results.")
|
|
28
|
+
choice_file = choose_from_options(multi=False, options=files, fzf=True, msg="Choose one option")
|
|
29
|
+
choice_file = PathExtended(choice_file)
|
|
30
|
+
else:
|
|
31
|
+
choice_file = path_obj
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
repo_root = get_repo_root(Path(choice_file))
|
|
35
|
+
print(f"💾 Selected file: {choice_file}.\nRepo root: {repo_root}")
|
|
36
|
+
ve_root_from_file, ipy_profile = get_ve_path_and_ipython_profile(choice_file)
|
|
37
|
+
if ipy_profile is None:
|
|
38
|
+
ipy_profile = "default"
|
|
39
|
+
|
|
40
|
+
_activate_ve_line = get_ve_activate_line(ve_root=ve_root_from_file or "$HOME/code/machineconfig/.venv")
|
|
41
|
+
|
|
42
|
+
# ========================= choosing function to run
|
|
43
|
+
if function is None or function.strip() == "":
|
|
44
|
+
from machineconfig.scripts.python.fire_jobs_route_helper import choose_function_or_lines
|
|
45
|
+
choice_function, choice_file, _kwargs_dict = choose_function_or_lines(choice_file, kwargs_dict={})
|
|
46
|
+
else:
|
|
47
|
+
choice_function = function
|
|
48
|
+
|
|
49
|
+
from machineconfig.cluster.sessions_managers.zellij_local import run_zellij_layout
|
|
50
|
+
from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
|
|
51
|
+
layout: LayoutConfig = {"layoutName": "fireNprocess", "layoutTabs": []}
|
|
52
|
+
for an_arg in range(num_process):
|
|
53
|
+
layout["layoutTabs"].append({"tabName": f"tab{an_arg}", "startDir": str(PathExtended.cwd()), "command": f"uv run -m fire {choice_file} {choice_function} --idx={an_arg} --idx_max={num_process}"})
|
|
54
|
+
print(layout)
|
|
55
|
+
run_zellij_layout(layout_config=layout)
|
|
56
|
+
|
|
@@ -1,34 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/bash
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
echo """
|
|
5
|
-
#=======================================================================
|
|
6
|
-
🔄 REPOSITORIES SETUP | Cloning project codebases
|
|
7
|
-
#=======================================================================
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
echo """📥 Setting up repositories...
|
|
11
|
-
🐊 crocodile - Main utility package
|
|
12
|
-
🔧 machineconfig - System configuration tools
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
mkdir -p $HOME/code
|
|
16
|
-
cd $HOME/code
|
|
17
|
-
# Setup crocodile repository
|
|
18
|
-
if [ -d "crocodile" ]; then
|
|
19
|
-
echo """🔄 crocodile directory exists, updating...
|
|
20
|
-
"""
|
|
21
|
-
cd crocodile
|
|
22
|
-
git reset --hard
|
|
23
|
-
git pull
|
|
24
|
-
cd ..
|
|
25
|
-
else
|
|
26
|
-
echo """⏳ Cloning crocodile repository...
|
|
27
|
-
"""
|
|
28
|
-
git clone https://github.com/thisismygitrepo/crocodile.git --depth 4
|
|
29
|
-
fi
|
|
30
|
-
|
|
31
|
-
# Setup machineconfig repository
|
|
32
4
|
cd $HOME/code
|
|
33
5
|
if [ -d "machineconfig" ]; then
|
|
34
6
|
echo """🔄 machineconfig directory exists, updating...
|
|
@@ -45,4 +17,4 @@ fi
|
|
|
45
17
|
|
|
46
18
|
cd $HOME/code/machineconfig
|
|
47
19
|
$HOME/.local/bin/uv sync --no-dev
|
|
48
|
-
$HOME/.local/bin/uv cache clean
|
|
20
|
+
# $HOME/.local/bin/uv cache clean
|
|
@@ -9,18 +9,6 @@ if (-not (Get-Command git.exe -ErrorAction SilentlyContinue)) {
|
|
|
9
9
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
# Setup crocodile repository
|
|
13
|
-
if (Test-Path "crocodile") {
|
|
14
|
-
Write-Host "🔄 crocodile directory exists, updating..."
|
|
15
|
-
Set-Location crocodile
|
|
16
|
-
git reset --hard
|
|
17
|
-
git pull
|
|
18
|
-
Set-Location ..
|
|
19
|
-
} else {
|
|
20
|
-
Write-Host "⏳ Cloning crocodile repository..."
|
|
21
|
-
git clone https://github.com/thisismygitrepo/crocodile.git --depth 4
|
|
22
|
-
}
|
|
23
|
-
|
|
24
12
|
# Setup machineconfig repository
|
|
25
13
|
if (Test-Path "machineconfig") {
|
|
26
14
|
Write-Host "🔄 machineconfig directory exists, updating..."
|
|
@@ -12,12 +12,10 @@ class Read:
|
|
|
12
12
|
suffix = Path(path).suffix[1:]
|
|
13
13
|
if suffix == "": raise ValueError(f"File type could not be inferred from suffix. Suffix is empty. Path: {path}")
|
|
14
14
|
if suffix in ("sqlite", "sqlite3", "db", "duckdb"):
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
# return res
|
|
20
|
-
raise NotImplementedError("Reading database files is not implemented yet. Use `crocodile.database.DBMS` to connect to the database file.")
|
|
15
|
+
from machineconfig.utils.files.dbms import DBMS
|
|
16
|
+
res = DBMS.from_local_db(path=path)
|
|
17
|
+
print(res.describe_db())
|
|
18
|
+
return res
|
|
21
19
|
try: return getattr(Read, suffix)(str(path), **kwargs)
|
|
22
20
|
except AttributeError as err:
|
|
23
21
|
if "type object 'Read' has no attribute" not in str(err): raise AttributeError(err) from err
|
|
@@ -110,7 +110,7 @@ encryption = ssl
|
|
|
110
110
|
|
|
111
111
|
def send_message(self, to: str, subject: str, body: str, txt_to_html: bool = True, attachments: Optional[list[Any]] = None):
|
|
112
112
|
_ = attachments
|
|
113
|
-
body += "\n\nThis is an automated email sent via
|
|
113
|
+
body += "\n\nThis is an automated email sent via machineconfig.comms script."
|
|
114
114
|
# msg = message.EmailMessage()
|
|
115
115
|
msg = MIMEMultipart("alternative")
|
|
116
116
|
msg["subject"] = subject
|
machineconfig/utils/ssh.py
CHANGED
|
@@ -8,20 +8,9 @@ from machineconfig.utils.accessories import pprint
|
|
|
8
8
|
# from machineconfig.utils.ve import get_ve_activate_line
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def get_header(wdir: OPLike
|
|
12
|
-
if toolbox:
|
|
13
|
-
toobox_code = """
|
|
14
|
-
try:
|
|
15
|
-
from crocodile.toolbox import *
|
|
16
|
-
except ImportError:
|
|
17
|
-
print("Crocodile not found, skipping import.")
|
|
18
|
-
pass
|
|
19
|
-
"""
|
|
20
|
-
else:
|
|
21
|
-
toobox_code = "# No toolbox import."
|
|
11
|
+
def get_header(wdir: OPLike):
|
|
22
12
|
return f"""
|
|
23
13
|
# >> Code prepended
|
|
24
|
-
{toobox_code}
|
|
25
14
|
{'''sys.path.insert(0, r'{wdir}') ''' if wdir is not None else "# No path insertion."}
|
|
26
15
|
# >> End of header, start of script passed
|
|
27
16
|
"""
|
|
@@ -236,7 +225,7 @@ class SSH: # inferior alternative: https://github.com/fabric/fabric
|
|
|
236
225
|
assert '"' not in cmd, 'Avoid using `"` in your command. I dont know how to handle this when passing is as command to python in pwsh command.'
|
|
237
226
|
if not return_obj:
|
|
238
227
|
return self.run(
|
|
239
|
-
cmd=f"""uv run --no-dev --project $HOME/code/machineconfig -c "{get_header(wdir=None
|
|
228
|
+
cmd=f"""uv run --no-dev --project $HOME/code/machineconfig -c "{get_header(wdir=None)}{cmd}\n""" + '"',
|
|
240
229
|
desc=desc or f"run_py on {self.get_remote_repr()}",
|
|
241
230
|
verbose=verbose,
|
|
242
231
|
strict_err=strict_err,
|