machineconfig 3.81__py3-none-any.whl → 3.82__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/scripts/python/fire_jobs.py +59 -6
- machineconfig/scripts/python/fire_jobs_args_helper.py +2 -38
- machineconfig/scripts/python/ftpx.py +55 -48
- machineconfig/scripts/python/repos.py +43 -44
- {machineconfig-3.81.dist-info → machineconfig-3.82.dist-info}/METADATA +1 -1
- {machineconfig-3.81.dist-info → machineconfig-3.82.dist-info}/RECORD +9 -12
- {machineconfig-3.81.dist-info → machineconfig-3.82.dist-info}/entry_points.txt +3 -3
- machineconfig/scripts/python/archive/im2text.py +0 -34
- machineconfig/scripts/python/archive/tmate_conn.py +0 -41
- machineconfig/scripts/python/archive/tmate_start.py +0 -44
- {machineconfig-3.81.dist-info → machineconfig-3.82.dist-info}/WHEEL +0 -0
- {machineconfig-3.81.dist-info → machineconfig-3.82.dist-info}/top_level.txt +0 -0
|
@@ -17,11 +17,12 @@ from machineconfig.utils.path_helper import match_file_name, sanitize_path
|
|
|
17
17
|
|
|
18
18
|
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
19
19
|
from machineconfig.utils.accessories import get_repo_root, randstr
|
|
20
|
-
from machineconfig.scripts.python.fire_jobs_args_helper import
|
|
20
|
+
from machineconfig.scripts.python.fire_jobs_args_helper import FireJobArgs, extract_kwargs
|
|
21
21
|
import platform
|
|
22
|
-
from typing import Optional
|
|
22
|
+
from typing import Optional, Annotated
|
|
23
23
|
from pathlib import Path
|
|
24
24
|
import tomllib
|
|
25
|
+
import typer
|
|
25
26
|
# import os
|
|
26
27
|
|
|
27
28
|
|
|
@@ -328,12 +329,64 @@ python -m machineconfig.cluster.templates.cli_click --file {choice_file} """
|
|
|
328
329
|
subprocess.run(command, shell=True, check=True)
|
|
329
330
|
|
|
330
331
|
|
|
331
|
-
def main(
|
|
332
|
-
|
|
332
|
+
def main(
|
|
333
|
+
path: Annotated[str, typer.Argument(help="The directory containing the jobs")] = ".",
|
|
334
|
+
function: Annotated[Optional[str], typer.Argument(help="Function to run")] = None,
|
|
335
|
+
ve: Annotated[str, typer.Option("--ve", "-v", help="Virtual environment name")] = "",
|
|
336
|
+
cmd: Annotated[bool, typer.Option("--cmd", "-B", help="Create a cmd fire command to launch the job asynchronously")] = False,
|
|
337
|
+
interactive: Annotated[bool, typer.Option("--interactive", "-i", help="Whether to run the job interactively using IPython")] = False,
|
|
338
|
+
debug: Annotated[bool, typer.Option("--debug", "-d", help="Enable debug mode")] = False,
|
|
339
|
+
choose_function: Annotated[bool, typer.Option("--choose_function", "-c", help="Choose function interactively")] = False,
|
|
340
|
+
loop: Annotated[bool, typer.Option("--loop", "-l", help="Infinite recursion (runs again after completion/interruption)")] = False,
|
|
341
|
+
jupyter: Annotated[bool, typer.Option("--jupyter", "-j", help="Open in a jupyter notebook")] = False,
|
|
342
|
+
submit_to_cloud: Annotated[bool, typer.Option("--submit_to_cloud", "-C", help="Submit to cloud compute")] = False,
|
|
343
|
+
remote: Annotated[bool, typer.Option("--remote", "-r", help="Launch on a remote machine")] = False,
|
|
344
|
+
module: Annotated[bool, typer.Option("--module", "-m", help="Launch the main file")] = False,
|
|
345
|
+
streamlit: Annotated[bool, typer.Option("--streamlit", "-S", help="Run as streamlit app")] = False,
|
|
346
|
+
environment: Annotated[str, typer.Option("--environment", "-E", help="Choose ip, localhost, hostname or arbitrary url")] = "",
|
|
347
|
+
holdDirectory: Annotated[bool, typer.Option("--holdDirectory", "-D", help="Hold current directory and avoid cd'ing to the script directory")] = False,
|
|
348
|
+
PathExport: Annotated[bool, typer.Option("--PathExport", "-P", help="Augment the PYTHONPATH with repo root")] = False,
|
|
349
|
+
git_pull: Annotated[bool, typer.Option("--git_pull", "-g", help="Start by pulling the git repo")] = False,
|
|
350
|
+
optimized: Annotated[bool, typer.Option("--optimized", "-O", help="Run the optimized version of the function")] = False,
|
|
351
|
+
Nprocess: Annotated[int, typer.Option("--Nprocess", "-p", help="Number of processes to use")] = 1,
|
|
352
|
+
zellij_tab: Annotated[Optional[str], typer.Option("--zellij_tab", "-z", help="Open in a new zellij tab")] = None,
|
|
353
|
+
watch: Annotated[bool, typer.Option("--watch", "-w", help="Watch the file for changes")] = False,
|
|
354
|
+
kw: Annotated[Optional[list[str]], typer.Option("--kw", help="Keyword arguments to pass to the function in the form of k1 v1 k2 v2 ... (meaning k1=v1, k2=v2, etc)")] = None,
|
|
355
|
+
layout: Annotated[bool, typer.Option("--layout", "-L", help="Use layout configuration (Zellij Or WindowsTerminal)")] = False,
|
|
356
|
+
) -> None:
|
|
357
|
+
"""Main function to process fire jobs arguments."""
|
|
358
|
+
args = FireJobArgs(
|
|
359
|
+
path=path,
|
|
360
|
+
function=function,
|
|
361
|
+
ve=ve,
|
|
362
|
+
cmd=cmd,
|
|
363
|
+
interactive=interactive,
|
|
364
|
+
debug=debug,
|
|
365
|
+
choose_function=choose_function,
|
|
366
|
+
loop=loop,
|
|
367
|
+
jupyter=jupyter,
|
|
368
|
+
submit_to_cloud=submit_to_cloud,
|
|
369
|
+
remote=remote,
|
|
370
|
+
module=module,
|
|
371
|
+
streamlit=streamlit,
|
|
372
|
+
environment=environment,
|
|
373
|
+
holdDirectory=holdDirectory,
|
|
374
|
+
PathExport=PathExport,
|
|
375
|
+
git_pull=git_pull,
|
|
376
|
+
optimized=optimized,
|
|
377
|
+
Nprocess=Nprocess,
|
|
378
|
+
zellij_tab=zellij_tab,
|
|
379
|
+
watch=watch,
|
|
380
|
+
kw=kw,
|
|
381
|
+
layout=layout,
|
|
382
|
+
)
|
|
333
383
|
route(args)
|
|
334
384
|
|
|
335
385
|
|
|
386
|
+
def main_from_parser():
|
|
387
|
+
typer.run(main)
|
|
388
|
+
|
|
389
|
+
|
|
336
390
|
if __name__ == "__main__":
|
|
337
391
|
# options, func_args = parse_pyfile(file_path="C:/Users/aalsaf01/code/machineconfig/myresources/crocodile/core.py")
|
|
338
|
-
|
|
339
|
-
route(args)
|
|
392
|
+
pass
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
|
-
from typing import Optional
|
|
3
|
-
import
|
|
2
|
+
from typing import Optional, Annotated
|
|
3
|
+
import typer
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
@dataclass
|
|
@@ -32,42 +32,6 @@ class FireJobArgs:
|
|
|
32
32
|
layout: bool = False
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
def get_args() -> FireJobArgs:
|
|
36
|
-
parser = argparse.ArgumentParser()
|
|
37
|
-
parser.add_argument("path", nargs="?", type=str, help="The directory containing the jobs", default=".")
|
|
38
|
-
parser.add_argument("function", nargs="?", type=str, help="Fuction to run", default=None)
|
|
39
|
-
parser.add_argument("--ve", "-v", type=str, help="virtual enviroment name", default="")
|
|
40
|
-
parser.add_argument("--cmd", "-B", action="store_true", help="Create a cmd fire command to launch the the job asynchronously.")
|
|
41
|
-
parser.add_argument("--interactive", "-i", action="store_true", help="Whether to run the job interactively using IPython")
|
|
42
|
-
parser.add_argument("--debug", "-d", action="store_true", help="debug")
|
|
43
|
-
parser.add_argument("--choose_function", "-c", action="store_true", help="debug")
|
|
44
|
-
parser.add_argument("--loop", "-l", action="store_true", help="infinite recusion (runs again after completion/interruption)")
|
|
45
|
-
parser.add_argument("--jupyter", "-j", action="store_true", help="open in a jupyter notebook")
|
|
46
|
-
parser.add_argument("--submit_to_cloud", "-C", action="store_true", help="submit to cloud compute")
|
|
47
|
-
parser.add_argument("--remote", "-r", action="store_true", help="launch on a remote machine")
|
|
48
|
-
parser.add_argument("--module", "-m", action="store_true", help="launch the main file")
|
|
49
|
-
parser.add_argument("--streamlit", "-S", action="store_true", help="run as streamlit app")
|
|
50
|
-
parser.add_argument("--environment", "-E", type=str, help="Choose ip, localhost, hostname or arbitrary url", default="")
|
|
51
|
-
parser.add_argument("--holdDirectory", "-D", action="store_true", help="hold current directory and avoid cd'ing to the script directory")
|
|
52
|
-
parser.add_argument("--PathExport", "-P", action="store_true", help="augment the PYTHONPATH with repo root.")
|
|
53
|
-
parser.add_argument("--git_pull", "-g", action="store_true", help="Start by pulling the git repo")
|
|
54
|
-
parser.add_argument("--optimized", "-O", action="store_true", help="Run the optimized version of the function")
|
|
55
|
-
parser.add_argument("--Nprocess", "-p", type=int, help="Number of processes to use", default=1)
|
|
56
|
-
parser.add_argument("--zellij_tab", "-z", type=str, dest="zellij_tab", help="open in a new zellij tab")
|
|
57
|
-
parser.add_argument("--watch", "-w", action="store_true", help="watch the file for changes")
|
|
58
|
-
parser.add_argument("--kw", nargs="*", default=None, help="keyword arguments to pass to the function in the form of k1 v1 k2 v2 ... (meaning k1=v1, k2=v2, etc)")
|
|
59
|
-
parser.add_argument("--layout", "-L", action="store_true", help="use layout configuration (Zellij Or WindowsTerminal)")
|
|
60
|
-
|
|
61
|
-
try:
|
|
62
|
-
args_raw = parser.parse_args()
|
|
63
|
-
except Exception as ex:
|
|
64
|
-
print(f"❌ Failed to parse arguments: {ex}")
|
|
65
|
-
parser.print_help()
|
|
66
|
-
raise ex
|
|
67
|
-
args = FireJobArgs(**vars(args_raw))
|
|
68
|
-
return args
|
|
69
|
-
|
|
70
|
-
|
|
71
35
|
def extract_kwargs(args: FireJobArgs) -> dict[str, object]:
|
|
72
36
|
str2obj = {"True": True, "False": False, "None": None}
|
|
73
37
|
if args.kw is not None:
|
|
@@ -6,39 +6,40 @@ Currently, the only way to work around this is to predifine the host in ~/.ssh/c
|
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
import
|
|
9
|
+
import typer
|
|
10
|
+
from typing_extensions import Annotated
|
|
10
11
|
from machineconfig.utils.ssh import SSH
|
|
11
12
|
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
12
13
|
from machineconfig.scripts.python.helpers.helpers2 import ES
|
|
13
14
|
from machineconfig.utils.accessories import pprint
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
def main(
|
|
17
|
+
def main(
|
|
18
|
+
source: Annotated[str, typer.Argument(help="Source path (machine:path)")],
|
|
19
|
+
target: Annotated[str, typer.Argument(help="Target path (machine:path)")],
|
|
20
|
+
recursive: Annotated[bool, typer.Option("--recursive", "-r", help="Send recursively.")] = False,
|
|
21
|
+
zipFirst: Annotated[bool, typer.Option("--zipFirst", "-z", help="Zip before sending.")] = False,
|
|
22
|
+
cloud: Annotated[bool, typer.Option("--cloud", "-c", help="Transfer through the cloud.")] = False,
|
|
23
|
+
) -> None:
|
|
17
24
|
print("""
|
|
18
25
|
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
19
26
|
┃ 🚀 FTP File Transfer
|
|
20
27
|
┃ 📋 Starting transfer process...
|
|
21
28
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━""")
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
parser.add_argument("--zipFirst", "-z", help="Zip before sending.", action="store_true") # default is False
|
|
30
|
-
parser.add_argument("--cloud", "-c", help="Transfer through the cloud.", action="store_true") # default is False
|
|
31
|
-
|
|
32
|
-
args = parser.parse_args()
|
|
33
|
-
|
|
34
|
-
if ":" in args.source and (args.source[1] != ":" if len(args.source) > 1 else True): # avoid the case of "C:/":
|
|
29
|
+
|
|
30
|
+
# Initialize variables
|
|
31
|
+
resolved_source: str | None = None
|
|
32
|
+
resolved_target: str | None = None
|
|
33
|
+
machine: str = ""
|
|
34
|
+
|
|
35
|
+
if ":" in source and (source[1] != ":" if len(source) > 1 else True): # avoid the case of "C:/":
|
|
35
36
|
source_is_remote = True
|
|
36
37
|
|
|
37
38
|
# calculating source:
|
|
38
|
-
source_parts =
|
|
39
|
+
source_parts = source.split(":")
|
|
39
40
|
machine = source_parts[0]
|
|
40
41
|
if len(source_parts) > 1 and source_parts[1] == ES: # the source path is to be inferred from target.
|
|
41
|
-
if
|
|
42
|
+
if target == ES:
|
|
42
43
|
raise ValueError(f"""
|
|
43
44
|
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
44
45
|
┃ ❌ Configuration Error
|
|
@@ -46,21 +47,22 @@ def main():
|
|
|
46
47
|
┃ This creates a cyclical inference dependency
|
|
47
48
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━""")
|
|
48
49
|
else:
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
target_path_obj = PathExtended(target).expanduser().absolute()
|
|
51
|
+
resolved_source = target_path_obj.collapseuser().as_posix()
|
|
52
|
+
resolved_target = target
|
|
51
53
|
else:
|
|
52
|
-
|
|
53
|
-
if
|
|
54
|
-
|
|
54
|
+
resolved_source = ":".join(source.split(":")[1:])
|
|
55
|
+
if target == ES:
|
|
56
|
+
resolved_target = None
|
|
55
57
|
else:
|
|
56
|
-
|
|
58
|
+
resolved_target = PathExtended(target).expanduser().absolute().as_posix()
|
|
57
59
|
|
|
58
|
-
elif ":" in
|
|
60
|
+
elif ":" in target and (target[1] != ":" if len(target) > 1 else True): # avoid the case of "C:/":
|
|
59
61
|
source_is_remote = False
|
|
60
|
-
target_parts =
|
|
62
|
+
target_parts = target.split(":")
|
|
61
63
|
machine = target_parts[0]
|
|
62
64
|
if len(target_parts) > 1 and target_parts[1] == ES:
|
|
63
|
-
if
|
|
65
|
+
if source == ES:
|
|
64
66
|
raise ValueError(f"""
|
|
65
67
|
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
66
68
|
┃ ❌ Configuration Error
|
|
@@ -68,14 +70,14 @@ def main():
|
|
|
68
70
|
┃ This creates a cyclical inference dependency
|
|
69
71
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━""")
|
|
70
72
|
else:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
resolved_source = source
|
|
74
|
+
resolved_target = None
|
|
73
75
|
else:
|
|
74
|
-
|
|
75
|
-
if
|
|
76
|
-
|
|
76
|
+
resolved_target = ":".join(target.split(":")[1:])
|
|
77
|
+
if source == ES:
|
|
78
|
+
resolved_source = None
|
|
77
79
|
else:
|
|
78
|
-
|
|
80
|
+
resolved_source = PathExtended(source).expanduser().absolute().as_posix()
|
|
79
81
|
|
|
80
82
|
else:
|
|
81
83
|
raise ValueError("""
|
|
@@ -85,7 +87,7 @@ def main():
|
|
|
85
87
|
┃ Format should be: machine:path
|
|
86
88
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━""")
|
|
87
89
|
|
|
88
|
-
pprint({"source": str(
|
|
90
|
+
pprint({"source": str(resolved_source), "target": str(resolved_target), "machine": machine}, "CLI Resolution")
|
|
89
91
|
|
|
90
92
|
from paramiko.ssh_exception import AuthenticationException # type: ignore
|
|
91
93
|
|
|
@@ -105,43 +107,43 @@ def main():
|
|
|
105
107
|
pwd = getpass.getpass()
|
|
106
108
|
ssh = SSH(rf"{machine}", pwd=pwd)
|
|
107
109
|
|
|
108
|
-
if
|
|
110
|
+
if cloud:
|
|
109
111
|
print("""
|
|
110
112
|
┌────────────────────────────────────────────────────────────────
|
|
111
113
|
│ ☁️ Cloud Transfer Mode
|
|
112
114
|
│ Uploading from remote to cloud...
|
|
113
115
|
└────────────────────────────────────────────────────────────────""")
|
|
114
|
-
ssh.run(f"cloud_copy {
|
|
116
|
+
ssh.run(f"cloud_copy {resolved_source} :^", desc="Uploading from remote to the cloud.").print()
|
|
115
117
|
print("""
|
|
116
118
|
┌────────────────────────────────────────────────────────────────
|
|
117
119
|
│ ⬇️ Cloud Transfer Mode
|
|
118
120
|
│ Downloading from cloud to local...
|
|
119
121
|
└────────────────────────────────────────────────────────────────""")
|
|
120
|
-
ssh.run_locally(f"cloud_copy :^ {
|
|
121
|
-
received_file = PathExtended(
|
|
122
|
+
ssh.run_locally(f"cloud_copy :^ {resolved_target}").print()
|
|
123
|
+
received_file = PathExtended(resolved_target) # type: ignore
|
|
122
124
|
else:
|
|
123
125
|
if source_is_remote:
|
|
124
|
-
assert
|
|
126
|
+
assert resolved_source is not None, """
|
|
125
127
|
❌ Path Error: Source must be a remote path (machine:path)"""
|
|
126
128
|
print(f"""
|
|
127
129
|
┌────────────────────────────────────────────────────────────────
|
|
128
130
|
│ 📥 Transfer Mode: Remote → Local
|
|
129
|
-
│ Source: {
|
|
130
|
-
│ Target: {
|
|
131
|
-
│ Options: {"ZIP compression" if
|
|
131
|
+
│ Source: {resolved_source}
|
|
132
|
+
│ Target: {resolved_target}
|
|
133
|
+
│ Options: {"ZIP compression" if zipFirst else "No compression"}, {"Recursive" if recursive else "Non-recursive"}
|
|
132
134
|
└────────────────────────────────────────────────────────────────""")
|
|
133
|
-
received_file = ssh.copy_to_here(source=
|
|
135
|
+
received_file = ssh.copy_to_here(source=resolved_source, target=resolved_target, z=zipFirst, r=recursive)
|
|
134
136
|
else:
|
|
135
|
-
assert
|
|
137
|
+
assert resolved_source is not None, """
|
|
136
138
|
❌ Path Error: Target must be a remote path (machine:path)"""
|
|
137
139
|
print(f"""
|
|
138
140
|
┌────────────────────────────────────────────────────────────────
|
|
139
141
|
│ 📤 Transfer Mode: Local → Remote
|
|
140
|
-
│ Source: {
|
|
141
|
-
│ Target: {
|
|
142
|
-
│ Options: {"ZIP compression" if
|
|
142
|
+
│ Source: {resolved_source}
|
|
143
|
+
│ Target: {resolved_target}
|
|
144
|
+
│ Options: {"ZIP compression" if zipFirst else "No compression"}, {"Recursive" if recursive else "Non-recursive"}
|
|
143
145
|
└────────────────────────────────────────────────────────────────""")
|
|
144
|
-
received_file = ssh.copy_from_here(source=
|
|
146
|
+
received_file = ssh.copy_from_here(source=resolved_source, target=resolved_target, z=zipFirst, r=recursive)
|
|
145
147
|
|
|
146
148
|
if source_is_remote and isinstance(received_file, PathExtended):
|
|
147
149
|
print(f"""
|
|
@@ -157,5 +159,10 @@ def main():
|
|
|
157
159
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━""")
|
|
158
160
|
|
|
159
161
|
|
|
162
|
+
def main_from_parser() -> None:
|
|
163
|
+
"""Entry point function that uses typer to parse arguments and call main."""
|
|
164
|
+
typer.run(main)
|
|
165
|
+
|
|
166
|
+
|
|
160
167
|
if __name__ == "__main__":
|
|
161
|
-
|
|
168
|
+
main_from_parser()
|
|
@@ -13,9 +13,9 @@ from machineconfig.scripts.python.repos_helper_update import update_repository
|
|
|
13
13
|
from machineconfig.scripts.python.repos_helper_record import main as record_repos
|
|
14
14
|
from machineconfig.scripts.python.repos_helper_clone import clone_repos
|
|
15
15
|
|
|
16
|
-
import
|
|
16
|
+
import typer
|
|
17
17
|
from enum import Enum
|
|
18
|
-
from typing import Optional
|
|
18
|
+
from typing import Annotated, Optional
|
|
19
19
|
|
|
20
20
|
from rich import print as pprint
|
|
21
21
|
|
|
@@ -83,69 +83,64 @@ def git_action(path: PathExtended, action: GitAction, mess: Optional[str] = None
|
|
|
83
83
|
return True
|
|
84
84
|
|
|
85
85
|
|
|
86
|
-
def main(
|
|
86
|
+
def main(
|
|
87
|
+
directory: Annotated[str, typer.Argument(help="📁 Folder containing repos to record or a specs JSON file to follow.")] = "",
|
|
88
|
+
push: Annotated[bool, typer.Option("--push", help="🚀 Push changes.")] = False,
|
|
89
|
+
pull: Annotated[bool, typer.Option("--pull", help="⬇️ Pull changes.")] = False,
|
|
90
|
+
commit: Annotated[bool, typer.Option("--commit", help="💾 Commit changes.")] = False,
|
|
91
|
+
all: Annotated[bool, typer.Option("--all", help="🔄 Pull, commit, and push changes.")] = False,
|
|
92
|
+
record: Annotated[bool, typer.Option("--record", help="📝 Record repositories.")] = False,
|
|
93
|
+
clone: Annotated[bool, typer.Option("--clone", help="📥 Clone repositories from record.")] = False,
|
|
94
|
+
checkout: Annotated[bool, typer.Option("--checkout", help="🔀 Check out to versions provided in a JSON file.")] = False,
|
|
95
|
+
checkout_to_branch: Annotated[bool, typer.Option("--checkout-to-branch", help="🔀 Check out to the main branch.")] = False,
|
|
96
|
+
recursive: Annotated[bool, typer.Option("--recursive", "-r", help="🔍 Recursive flag.")] = False,
|
|
97
|
+
no_sync: Annotated[bool, typer.Option("--no-sync", help="🚫 Disable automatic uv sync after pulls.")] = False,
|
|
98
|
+
cloud: Annotated[Optional[str], typer.Option("--cloud", "-c", help="☁️ Cloud storage option.")] = None,
|
|
99
|
+
) -> None:
|
|
87
100
|
print("\n" + "=" * 50)
|
|
88
101
|
print("📂 Welcome to the Repository Manager")
|
|
89
102
|
print("=" * 50 + "\n")
|
|
90
103
|
|
|
91
|
-
|
|
92
|
-
# POSITIONAL
|
|
93
|
-
parser.add_argument("directory", help="📁 Folder containing repos to record or a specs JSON file to follow.", default="")
|
|
94
|
-
# FLAGS
|
|
95
|
-
parser.add_argument("--push", help="🚀 Push changes.", action="store_true")
|
|
96
|
-
parser.add_argument("--pull", help="⬇️ Pull changes.", action="store_true")
|
|
97
|
-
parser.add_argument("--commit", help="💾 Commit changes.", action="store_true")
|
|
98
|
-
parser.add_argument("--all", help="🔄 Pull, commit, and push changes.", action="store_true")
|
|
99
|
-
parser.add_argument("--record", help="📝 Record repositories.", action="store_true")
|
|
100
|
-
parser.add_argument("--clone", help="📥 Clone repositories from record.", action="store_true")
|
|
101
|
-
parser.add_argument("--checkout", help="🔀 Check out to versions provided in a JSON file.", action="store_true")
|
|
102
|
-
parser.add_argument("--checkout_to_branch", help="🔀 Check out to the main branch.", action="store_true")
|
|
103
|
-
parser.add_argument("--recursive", "-r", help="🔍 Recursive flag.", action="store_true")
|
|
104
|
-
parser.add_argument("--no-sync", help="🚫 Disable automatic uv sync after pulls.", action="store_true")
|
|
105
|
-
# OPTIONAL
|
|
106
|
-
parser.add_argument("--cloud", "-c", help="☁️ Cloud storage option.", default=None)
|
|
107
|
-
args = parser.parse_args()
|
|
108
|
-
|
|
109
|
-
if args.directory == "":
|
|
104
|
+
if directory == "":
|
|
110
105
|
repos_root = PathExtended.home().joinpath("code") # it is a positional argument, can never be empty.
|
|
111
106
|
else:
|
|
112
|
-
repos_root = PathExtended(
|
|
107
|
+
repos_root = PathExtended(directory).expanduser().absolute()
|
|
113
108
|
|
|
114
|
-
auto_sync = not
|
|
109
|
+
auto_sync = not no_sync # Enable auto sync by default, disable with --no-sync
|
|
115
110
|
|
|
116
|
-
if
|
|
111
|
+
if record:
|
|
117
112
|
save_path = record_repos(repos_root=repos_root)
|
|
118
|
-
if
|
|
119
|
-
PathExtended(save_path).to_cloud(rel2home=True, cloud=
|
|
113
|
+
if cloud is not None:
|
|
114
|
+
PathExtended(save_path).to_cloud(rel2home=True, cloud=cloud)
|
|
120
115
|
|
|
121
|
-
elif
|
|
116
|
+
elif clone or checkout or checkout_to_branch:
|
|
122
117
|
print("\n📥 Cloning or checking out repositories...")
|
|
123
118
|
print(">>>>>>>>> Cloning Repos")
|
|
124
119
|
if not repos_root.exists() or repos_root.name != "repos.json":
|
|
125
120
|
repos_root = PathExtended(CONFIG_PATH).joinpath("repos").joinpath(repos_root.rel2home()).joinpath("repos.json")
|
|
126
121
|
if not repos_root.exists():
|
|
127
|
-
if
|
|
128
|
-
|
|
129
|
-
print(f"⚠️ Using default cloud: {
|
|
122
|
+
if cloud is None:
|
|
123
|
+
cloud_name: str = read_ini(DEFAULTS_PATH)["general"]["rclone_config_name"]
|
|
124
|
+
print(f"⚠️ Using default cloud: {cloud_name}")
|
|
130
125
|
else:
|
|
131
|
-
|
|
132
|
-
assert
|
|
133
|
-
repos_root.from_cloud(cloud=
|
|
134
|
-
assert (repos_root.exists() and repos_root.name == "repos.json") or
|
|
135
|
-
clone_repos(spec_path=repos_root, preferred_remote=None, checkout_branch_flag=
|
|
126
|
+
cloud_name = cloud
|
|
127
|
+
assert cloud_name is not None, f"Path {repos_root} does not exist and cloud was not passed. You can't clone without one of them."
|
|
128
|
+
repos_root.from_cloud(cloud=cloud_name, rel2home=True)
|
|
129
|
+
assert (repos_root.exists() and repos_root.name == "repos.json") or cloud is not None, f"Path {repos_root} does not exist and cloud was not passed. You can't clone without one of them."
|
|
130
|
+
clone_repos(spec_path=repos_root, preferred_remote=None, checkout_branch_flag=checkout_to_branch, checkout_commit_flag=checkout)
|
|
136
131
|
|
|
137
|
-
elif
|
|
132
|
+
elif all or commit or pull or push:
|
|
138
133
|
print(f"\n🔄 Performing Git actions on repositories @ `{repos_root}`...")
|
|
139
134
|
overall_success = True
|
|
140
135
|
for a_path in repos_root.search("*"):
|
|
141
136
|
print(f"{('Handling ' + str(a_path)).center(80, '-')}")
|
|
142
137
|
path_success = True
|
|
143
|
-
if
|
|
144
|
-
path_success = git_action(path=a_path, action=GitAction.pull, r=
|
|
145
|
-
if
|
|
146
|
-
path_success = git_action(a_path, action=GitAction.commit, r=
|
|
147
|
-
if
|
|
148
|
-
path_success = git_action(a_path, action=GitAction.push, r=
|
|
138
|
+
if pull or all:
|
|
139
|
+
path_success = git_action(path=a_path, action=GitAction.pull, r=recursive, auto_sync=auto_sync) and path_success
|
|
140
|
+
if commit or all:
|
|
141
|
+
path_success = git_action(a_path, action=GitAction.commit, r=recursive, auto_sync=auto_sync) and path_success
|
|
142
|
+
if push or all:
|
|
143
|
+
path_success = git_action(a_path, action=GitAction.push, r=recursive, auto_sync=auto_sync) and path_success
|
|
149
144
|
overall_success = overall_success and path_success
|
|
150
145
|
|
|
151
146
|
if overall_success:
|
|
@@ -156,5 +151,9 @@ def main():
|
|
|
156
151
|
print("❌ No action specified. Try passing --push, --pull, --commit, or --all.")
|
|
157
152
|
|
|
158
153
|
|
|
154
|
+
def main_from_parser() -> None:
|
|
155
|
+
typer.run(main)
|
|
156
|
+
|
|
157
|
+
|
|
159
158
|
if __name__ == "__main__":
|
|
160
|
-
|
|
159
|
+
main_from_parser()
|
|
@@ -179,11 +179,11 @@ machineconfig/scripts/python/fire_agents.py,sha256=_k1CcPaAp3B7h72tSczFDbLsqTg6F
|
|
|
179
179
|
machineconfig/scripts/python/fire_agents_help_launch.py,sha256=sTdjNz2pDinDMMjUAMN7OqH-KAUeHh6Aihr_zUvtM6k,6128
|
|
180
180
|
machineconfig/scripts/python/fire_agents_help_search.py,sha256=qIfSS_su2YJ1Gb0_lu4cbjlJlYMBw0v52NTGiSrGjk8,2991
|
|
181
181
|
machineconfig/scripts/python/fire_agents_load_balancer.py,sha256=QPiCbQq9j5REHStPdYqQcGNkz_rp5CjotqOpMY3v5TM,2099
|
|
182
|
-
machineconfig/scripts/python/fire_jobs.py,sha256=
|
|
183
|
-
machineconfig/scripts/python/fire_jobs_args_helper.py,sha256=
|
|
182
|
+
machineconfig/scripts/python/fire_jobs.py,sha256=W7JDckAWrpHlB3WHpULpZP3M22ORxvLO-6lcnRloHX8,20119
|
|
183
|
+
machineconfig/scripts/python/fire_jobs_args_helper.py,sha256=CeXmx0FJZlUSsQHcUmvHM2dQBmKcTNtTkha5PHaQQhc,1505
|
|
184
184
|
machineconfig/scripts/python/fire_jobs_layout_helper.py,sha256=Hj77uKgmNKSEBtnW0oCdRBwdKEuhzPxX1p81mRTBibo,3314
|
|
185
185
|
machineconfig/scripts/python/fire_jobs_streamlit_helper.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
186
|
-
machineconfig/scripts/python/ftpx.py,sha256=
|
|
186
|
+
machineconfig/scripts/python/ftpx.py,sha256=vqwhfkg3jVaAdjlWvrcPms2pUD7_c370jn2W6o5XArM,10269
|
|
187
187
|
machineconfig/scripts/python/get_zellij_cmd.py,sha256=e35-18hoXM9N3PFbvbizfkNY_-63iMicieWE3TbGcCQ,576
|
|
188
188
|
machineconfig/scripts/python/gh_models.py,sha256=3BLfW25mBRiPO5VKtVm-nMlKLv-PaZDw7mObajq6F6M,5538
|
|
189
189
|
machineconfig/scripts/python/mount_nfs.py,sha256=c8pWXimDWdgCkSskcnPgT-8ESPosil6Cvy2hGSaIBJE,3359
|
|
@@ -191,7 +191,7 @@ machineconfig/scripts/python/mount_nw_drive.py,sha256=iru6AtnTyvyuk6WxlK5R4lDkul
|
|
|
191
191
|
machineconfig/scripts/python/mount_ssh.py,sha256=rGY2pgtlnWMi0Rrge1aCdjtfbULrj2cyaStDoX-y2w4,2236
|
|
192
192
|
machineconfig/scripts/python/onetimeshare.py,sha256=bmGsNnskym5OWfIhpOfZG5jq3m89FS0a6dF5Sb8LaZM,2539
|
|
193
193
|
machineconfig/scripts/python/pomodoro.py,sha256=SPkfeoZGv8rylGiOyzQ7UK3aXZ3G2FIOuGkSuBUggOI,2019
|
|
194
|
-
machineconfig/scripts/python/repos.py,sha256=
|
|
194
|
+
machineconfig/scripts/python/repos.py,sha256=gU1gmYmiGTGDlZyIj3b1bC78yV5XZSXEkDD95WRqUnM,7376
|
|
195
195
|
machineconfig/scripts/python/repos_helper_clone.py,sha256=xW5YZEoNt3k7h9NIULhUhOnh53-B63eiXF2FjOl1IKQ,5535
|
|
196
196
|
machineconfig/scripts/python/repos_helper_record.py,sha256=YEEQORfEiLddOIIgePo5eEkyQUFruFg3kc8npMvRL-o,10927
|
|
197
197
|
machineconfig/scripts/python/repos_helper_update.py,sha256=AYyKIB7eQ48yoYmFjydIhRI1lV39TBv_S4_LCa-oKuQ,11042
|
|
@@ -229,9 +229,6 @@ machineconfig/scripts/python/ai/solutions/gemini/settings.json,sha256=hv0POw6ySh
|
|
|
229
229
|
machineconfig/scripts/python/ai/solutions/kilocode/privacy.md,sha256=oKOXnfFOdUuMlKwVf5MqeqCc24hZcjKE_e1MEXpijJI,117
|
|
230
230
|
machineconfig/scripts/python/ai/solutions/opencode/opencode.json,sha256=nahHKRw1dNzkUCS_vCX_fy2TisRtfg8DXH-D4N1iUVU,99
|
|
231
231
|
machineconfig/scripts/python/ai/solutions/opencode/opencode.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
232
|
-
machineconfig/scripts/python/archive/im2text.py,sha256=WLyic89vxi_pqQMzo-MOrGf39JEZjCdvDrXYUMVvZNY,1163
|
|
233
|
-
machineconfig/scripts/python/archive/tmate_conn.py,sha256=BiZQmYabl4K4-mbOpcb_R1JzYfEwxuAnk5FOciqGHFo,1231
|
|
234
|
-
machineconfig/scripts/python/archive/tmate_start.py,sha256=Hp7xv32u-fRuCG_f-Cy6qg0VemoaPOP-Pxs_gsFYcyg,1518
|
|
235
232
|
machineconfig/scripts/python/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
236
233
|
machineconfig/scripts/python/helpers/cloud_helpers.py,sha256=GA-bxXouUmknk9fyQAsPT-Xl3RG9-yBed71a2tu9Pig,4914
|
|
237
234
|
machineconfig/scripts/python/helpers/helpers2.py,sha256=ZdqeF1MLlaBRwoqsQAqnHi4b8rW0byFCBnbyCrPKkoA,7336
|
|
@@ -424,8 +421,8 @@ machineconfig/utils/schemas/fire_agents/fire_agents_input.py,sha256=CCs5ebomW1ac
|
|
|
424
421
|
machineconfig/utils/schemas/installer/installer_types.py,sha256=iAzcALc9z_FAQE9iuGHfX6Z0B1_n3Gt6eC0d6heYik0,599
|
|
425
422
|
machineconfig/utils/schemas/layouts/layout_types.py,sha256=OmiOX9xtakPz4l6IobWnpFHpbn95fitEE9q0YL1WxjQ,617
|
|
426
423
|
machineconfig/utils/schemas/repos/repos_types.py,sha256=ECVr-3IVIo8yjmYmVXX2mnDDN1SLSwvQIhx4KDDQHBQ,405
|
|
427
|
-
machineconfig-3.
|
|
428
|
-
machineconfig-3.
|
|
429
|
-
machineconfig-3.
|
|
430
|
-
machineconfig-3.
|
|
431
|
-
machineconfig-3.
|
|
424
|
+
machineconfig-3.82.dist-info/METADATA,sha256=lBIY_Ul0cOylp78PYNbNbIlXyzPRfyYGrWbBtFsrGiI,6998
|
|
425
|
+
machineconfig-3.82.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
426
|
+
machineconfig-3.82.dist-info/entry_points.txt,sha256=RwV4BmImYKp4GrXGqb_YDEI25O2_5mhsbvjUD6a0hps,1138
|
|
427
|
+
machineconfig-3.82.dist-info/top_level.txt,sha256=porRtB8qms8fOIUJgK-tO83_FeH6Bpe12oUVC670teA,14
|
|
428
|
+
machineconfig-3.82.dist-info/RECORD,,
|
|
@@ -6,14 +6,14 @@ cloud_repo_sync = machineconfig.scripts.python.cloud_repo_sync:args_parser
|
|
|
6
6
|
cloud_sync = machineconfig.scripts.python.cloud_sync:args_parser
|
|
7
7
|
croshell = machineconfig.scripts.python.croshell:build_parser
|
|
8
8
|
devops = machineconfig.scripts.python.devops:args_parser
|
|
9
|
-
fire = machineconfig.scripts.python.fire_jobs:
|
|
9
|
+
fire = machineconfig.scripts.python.fire_jobs:main_from_parser
|
|
10
10
|
fire_agents = machineconfig.scripts.python.fire_agents:main
|
|
11
|
-
ftpx = machineconfig.scripts.python.ftpx:
|
|
11
|
+
ftpx = machineconfig.scripts.python.ftpx:main_from_parser
|
|
12
12
|
initai = machineconfig.scripts.python.ai.initai:main
|
|
13
13
|
install = machineconfig.scripts.python.devops_devapps_install:main_with_parser
|
|
14
14
|
kill_process = machineconfig.utils.procs:main
|
|
15
15
|
mount_nfs = machineconfig.scripts.python.mount_nfs:main
|
|
16
16
|
mount_nw_drive = machineconfig.scripts.python.mount_nw_drive:main
|
|
17
|
-
repos = machineconfig.scripts.python.repos:
|
|
17
|
+
repos = machineconfig.scripts.python.repos:main_from_parser
|
|
18
18
|
start_slidev = machineconfig.scripts.python.start_slidev:main
|
|
19
19
|
wifi_conn = machineconfig.scripts.python.wifi_conn:main
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# """Convert image to text.
|
|
2
|
-
# """
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
# # import sys
|
|
6
|
-
# from rich.console import Console
|
|
7
|
-
# from rich.panel import Panel
|
|
8
|
-
# import pytesseract
|
|
9
|
-
# from PIL import Image
|
|
10
|
-
|
|
11
|
-
# console = Console()
|
|
12
|
-
|
|
13
|
-
# console.print(Panel("📸 Image to Text Converter", title="Status", expand=False))
|
|
14
|
-
|
|
15
|
-
# print("📷 Capturing image from webcam...")
|
|
16
|
-
# img_path = capture_from_webcam(show=False, wait=False, save=True)
|
|
17
|
-
# print(f"✅ Image captured and saved to: {img_path}")
|
|
18
|
-
|
|
19
|
-
# # img_rgb = cv2.cvtColor(img_cv, cv2.COLOR_BGR2RGB)
|
|
20
|
-
# # import cv2
|
|
21
|
-
# # img_cv = cv2.imread(r'C:\Users\alex\Downloads\name.jpg')
|
|
22
|
-
|
|
23
|
-
# # sys.path.insert(0, PathExtended.home().joinpath("AppData/Local/Tesseract-OCR").str)
|
|
24
|
-
# # import pytesseract
|
|
25
|
-
# # print(pytesseract.image_to_string(img_cv))
|
|
26
|
-
|
|
27
|
-
# print("\n🔍 Processing image with Tesseract OCR...")
|
|
28
|
-
# q = Terminal().run(f"cd ~/AppData/Local/Tesseract-OCR; pytesseract '{img_path}'", shell="pwsh").capture().op
|
|
29
|
-
|
|
30
|
-
# try:
|
|
31
|
-
# text = pytesseract.image_to_string(Image.open(img_path))
|
|
32
|
-
# console.print(Panel(text, title="📄 Extracted Text Result:", title_align="left", expand=False))
|
|
33
|
-
# except FileNotFoundError:
|
|
34
|
-
# print(f"Error: Image file not found at {img_path}")
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import argparse
|
|
2
|
-
import configparser
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
import random
|
|
5
|
-
import string
|
|
6
|
-
import os
|
|
7
|
-
from rich.console import Console
|
|
8
|
-
from rich.panel import Panel
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
console = Console()
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def get_conn_string(sess_name: str) -> str:
|
|
15
|
-
creds = configparser.ConfigParser()
|
|
16
|
-
creds.read(Path.home().joinpath("dotfiles/creds/tmate/creds.ini"))
|
|
17
|
-
sess_name = creds["sessions_names"][sess_name]
|
|
18
|
-
user_name = creds["keys"]["username"]
|
|
19
|
-
return f"{user_name}/{sess_name}@sgp1.tmate.io"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def main():
|
|
23
|
-
console.print(Panel("🔌 Tmate Connection Manager", title="[bold]Welcome[/bold]"))
|
|
24
|
-
|
|
25
|
-
parser = argparse.ArgumentParser(description="Tmate launcher")
|
|
26
|
-
parser.add_argument("sess_name", help="session name", default=random.choices(list(string.digits + string.ascii_letters), k=20))
|
|
27
|
-
args = parser.parse_args()
|
|
28
|
-
|
|
29
|
-
console.print(f"🔍 Looking up session: {args.sess_name}")
|
|
30
|
-
conn_string = get_conn_string(args.sess_name)
|
|
31
|
-
|
|
32
|
-
console.print(Panel(f"SSH Connection String: ssh {conn_string}", title="[bold green]SSH Connection[/bold green]"))
|
|
33
|
-
|
|
34
|
-
console.print("🚀 Connecting to tmate session...")
|
|
35
|
-
os.system(f"ssh {conn_string}")
|
|
36
|
-
|
|
37
|
-
console.print("✅ Connection closed")
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if __name__ == "__main__":
|
|
41
|
-
main()
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
"""Tmate"""
|
|
2
|
-
|
|
3
|
-
import argparse
|
|
4
|
-
import configparser
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
import random
|
|
7
|
-
import string
|
|
8
|
-
import os
|
|
9
|
-
from rich.console import Console
|
|
10
|
-
from rich.panel import Panel
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def main():
|
|
14
|
-
console = Console()
|
|
15
|
-
|
|
16
|
-
console.print(Panel("📡 Tmate Session Launcher", title="[bold blue]Welcome[/bold blue]", subtitle="Manage your tmate sessions effortlessly"))
|
|
17
|
-
|
|
18
|
-
console.print("[bold yellow]Loading credentials...[/bold yellow]")
|
|
19
|
-
creds = configparser.ConfigParser()
|
|
20
|
-
creds.read(Path.home().joinpath("dotfiles/creds/tmate/creds.ini"))
|
|
21
|
-
console.print("[green]Credentials loaded[/green]")
|
|
22
|
-
|
|
23
|
-
parser = argparse.ArgumentParser(description="Tmate launcher")
|
|
24
|
-
random_sess = random.choices(list(string.digits + string.ascii_letters), k=20)
|
|
25
|
-
_ = random_sess
|
|
26
|
-
parser.add_argument("sess_name", help="session name (new only with random string will be chosen if not passed)", default=None)
|
|
27
|
-
|
|
28
|
-
args = parser.parse_args()
|
|
29
|
-
|
|
30
|
-
console.print(f"🔍 Looking up session configuration: {args.sess_name}")
|
|
31
|
-
sess_name = creds["sessions_names"][args.sess_name]
|
|
32
|
-
api_key = creds["keys"]["api_key"]
|
|
33
|
-
|
|
34
|
-
console.print(Panel(f"🚀 Starting tmate session: {sess_name}", title="[bold green]Session Info[/bold green]"))
|
|
35
|
-
|
|
36
|
-
res = f"tmate -a ~/.ssh/authorized_keys -k {api_key} -n {sess_name} -F"
|
|
37
|
-
console.print("[bold cyan]Running:[/bold cyan] tmate with configured API key and session name")
|
|
38
|
-
os.system(res)
|
|
39
|
-
|
|
40
|
-
console.print("[green]Tmate session ended[/green]")
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if __name__ == "__main__":
|
|
44
|
-
main()
|
|
File without changes
|
|
File without changes
|