machineconfig 1.8__py3-none-any.whl → 1.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of machineconfig might be problematic. Click here for more details.
- machineconfig/__init__.py +4 -2
- machineconfig/jobs/python/check_installations.py +1 -1
- machineconfig/jobs/python_custom_installers/azuredatastudio.py +36 -0
- machineconfig/jobs/{script_installer → python_custom_installers}/bypass_paywall.py +8 -1
- machineconfig/jobs/{script_installer → python_custom_installers}/docker_desktop.py +14 -3
- machineconfig/jobs/python_custom_installers/gh.py +53 -0
- machineconfig/jobs/python_custom_installers/goes.py +35 -0
- machineconfig/jobs/python_custom_installers/helix.py +43 -0
- machineconfig/jobs/python_custom_installers/lvim.py +48 -0
- machineconfig/jobs/{script_installer → python_custom_installers}/ngrok.py +11 -1
- machineconfig/jobs/python_custom_installers/nvim.py +48 -0
- machineconfig/jobs/{script_installer/code.py → python_custom_installers/vscode.py} +11 -0
- machineconfig/jobs/python_custom_installers/wezterm.py +41 -0
- machineconfig/profile/create.py +4 -1
- machineconfig/scripts/python/choose_wezterm_theme.py +96 -0
- machineconfig/scripts/python/cloud_copy.py +5 -1
- machineconfig/scripts/python/cloud_mount.py +20 -10
- machineconfig/scripts/python/cloud_repo_sync.py +30 -22
- machineconfig/scripts/python/cloud_sync.py +4 -6
- machineconfig/scripts/python/croshell.py +17 -8
- machineconfig/scripts/python/devops_devapps_install.py +12 -6
- machineconfig/scripts/python/fire_jobs.py +92 -53
- machineconfig/scripts/python/ftpx.py +17 -7
- machineconfig/scripts/python/repos.py +5 -1
- machineconfig/scripts/python/start_terminals.py +1 -1
- machineconfig/utils/installer.py +98 -30
- machineconfig/utils/utils.py +6 -4
- machineconfig/utils/ve.py +37 -16
- machineconfig-1.9.dist-info/LICENSE +201 -0
- {machineconfig-1.8.dist-info → machineconfig-1.9.dist-info}/METADATA +155 -140
- {machineconfig-1.8.dist-info → machineconfig-1.9.dist-info}/RECORD +34 -28
- {machineconfig-1.8.dist-info → machineconfig-1.9.dist-info}/WHEEL +1 -1
- machineconfig/jobs/script_installer/azure_data_studio.py +0 -22
- machineconfig/jobs/script_installer/skim.py +0 -21
- machineconfig/jobs/script_installer/wezterm.py +0 -34
- /machineconfig/jobs/{script_installer → python_custom_installers}/__init__.py +0 -0
- {machineconfig-1.8.dist-info → machineconfig-1.9.dist-info}/top_level.txt +0 -0
|
@@ -20,6 +20,7 @@ def get_wt_cmd(wd1: P, wd2: P) -> str:
|
|
|
20
20
|
]
|
|
21
21
|
return " `; ".join(lines)
|
|
22
22
|
|
|
23
|
+
|
|
23
24
|
def get_zellij_cmd(wd1: P, wd2: P) -> str:
|
|
24
25
|
lines = [f""" zellij action new-tab --name gitdiff""",
|
|
25
26
|
f"""zellij action new-pane --direction down --name local --cwd ./data """,
|
|
@@ -65,38 +66,38 @@ def main(cloud: Optional[str] = None, path: Optional[str] = None, message: Optio
|
|
|
65
66
|
return ""
|
|
66
67
|
else: cloud_resolved = cloud
|
|
67
68
|
# repo_root = P(args.repo).expanduser().absolute()
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
repo_local_root = P.cwd() if path is None else P(path).expanduser().absolute()
|
|
70
|
+
repo_local_obj = install_n_import("git", "gitpython").Repo(repo_local_root, search_parent_directories=True)
|
|
71
|
+
repo_local_root = P(repo_local_obj.working_dir) # cwd might have been in a sub directory of repo_root, so its better to redefine it.
|
|
71
72
|
CONFIG_PATH.joinpath("remote").create()
|
|
72
|
-
|
|
73
|
+
repo_remote_root = CONFIG_PATH.joinpath("remote", repo_local_root.rel2home()) # .delete(sure=True)
|
|
73
74
|
try:
|
|
74
75
|
print("\n", "=============================== Downloading Remote Repo ====================================")
|
|
75
|
-
remote_path =
|
|
76
|
-
|
|
76
|
+
remote_path = repo_local_root.get_remote_path(rel2home=True, os_specific=False, root="myhome") + ".zip.enc"
|
|
77
|
+
repo_remote_root.from_cloud(remotepath=remote_path, cloud=cloud_resolved, unzip=True, decrypt=True, rel2home=True, os_specific=False, pwd=pwd)
|
|
77
78
|
except AssertionError:
|
|
78
79
|
print("Remote does not exist, creating it and exiting ... ")
|
|
79
|
-
|
|
80
|
+
repo_local_root.to_cloud(cloud=cloud_resolved, zip=True, encrypt=True, rel2home=True, pwd=pwd, os_specific=False)
|
|
80
81
|
return ""
|
|
81
|
-
|
|
82
|
-
if
|
|
83
|
-
print("=" * 50, '\n', f"WRANING: the remote `{
|
|
82
|
+
repo_remote_obj = install_n_import("git", "gitpython").Repo(repo_remote_root)
|
|
83
|
+
if repo_remote_obj.is_dirty():
|
|
84
|
+
print("=" * 50, '\n', f"WRANING: the remote `{repo_remote_root}` is dirty, please commit or stash changes before proceeding.", '\n', "=" * 50)
|
|
84
85
|
|
|
85
86
|
script = f"""
|
|
86
87
|
echo ""
|
|
87
88
|
echo "=============================== Committing Local Changes ==================================="
|
|
88
|
-
cd {
|
|
89
|
+
cd {repo_local_root}
|
|
89
90
|
git status
|
|
90
91
|
git add .
|
|
91
92
|
git commit -am "{message}"
|
|
92
93
|
echo ""
|
|
93
94
|
echo ""
|
|
94
95
|
echo "=============================== Pulling Latest From Remote ================================"
|
|
95
|
-
cd {
|
|
96
|
+
cd {repo_local_root}
|
|
96
97
|
echo '-> Trying to removing originEnc remote from local repo if it exists.'
|
|
97
98
|
git remote remove originEnc
|
|
98
99
|
echo '-> Adding originEnc remote to local repo'
|
|
99
|
-
git remote add originEnc {
|
|
100
|
+
git remote add originEnc {repo_remote_root}
|
|
100
101
|
echo '-> Fetching originEnc remote.'
|
|
101
102
|
git pull originEnc master
|
|
102
103
|
|
|
@@ -106,34 +107,41 @@ git pull originEnc master
|
|
|
106
107
|
|
|
107
108
|
if res.is_successful(strict_err=True, strict_returcode=True):
|
|
108
109
|
print("\n", "Pull succeeded, removing originEnc, the local copy of remote & pushing merged repo_root to remote ... ")
|
|
109
|
-
|
|
110
|
+
repo_remote_root.delete(sure=True)
|
|
110
111
|
from git.remote import Remote
|
|
111
|
-
Remote.remove(
|
|
112
|
+
Remote.remove(repo_local_obj, "originEnc")
|
|
112
113
|
if push:
|
|
113
|
-
|
|
114
|
+
repo_local_root.to_cloud(cloud=cloud_resolved, zip=True, encrypt=True, rel2home=True, pwd=pwd, os_specific=False)
|
|
114
115
|
else:
|
|
115
|
-
print(f"Failed to pull, keeping local copy of remote at {
|
|
116
|
+
print(f"Failed to pull, keeping local copy of remote at {repo_remote_root} ... ")
|
|
116
117
|
|
|
117
118
|
if push:
|
|
118
119
|
if skip_confirmation: resp = "y"
|
|
119
|
-
else: resp = input(f"Would you like to proceed syncing `{
|
|
120
|
+
else: resp = input(f"Would you like to proceed syncing `{repo_local_root}` to `{cloud_resolved}` by pushing local changes to remote and deleting local copy of remote? y/[n] ") or "n"
|
|
120
121
|
else: resp = "n"
|
|
121
122
|
|
|
122
123
|
if resp.lower() == "y":
|
|
123
|
-
delete_remote_repo_copy_and_push_local(remote_repo=
|
|
124
|
+
delete_remote_repo_copy_and_push_local(remote_repo=repo_remote_root.str, local_repo=repo_local_root.str, cloud=cloud_resolved)
|
|
124
125
|
else:
|
|
125
126
|
program = f"""
|
|
126
127
|
from machineconfig.scripts.python.cloud_repo_sync import delete_remote_repo_copy_and_push_local as func
|
|
127
|
-
func(remote_repo=r'{
|
|
128
|
+
func(remote_repo=r'{repo_remote_root.str}', local_repo=r'{repo_local_root.str}', cloud=r'{cloud_resolved}')
|
|
128
129
|
"""
|
|
129
130
|
shell_file = get_shell_file_executing_python_script(python_script=program)
|
|
130
131
|
print(f"When ready, use this snippet: \n. {shell_file}")
|
|
132
|
+
print(f"""
|
|
133
|
+
Or, if you want to delete local repo and replace with remote, run the following bash commands:
|
|
134
|
+
|
|
135
|
+
rm -rfd {repo_local_root}
|
|
136
|
+
mv {repo_remote_root} {repo_local_root}
|
|
137
|
+
|
|
138
|
+
""")
|
|
131
139
|
if platform.system() == "Windows":
|
|
132
|
-
program = get_wt_cmd(wd1=
|
|
140
|
+
program = get_wt_cmd(wd1=repo_local_root, wd2=repo_remote_root)
|
|
133
141
|
write_shell_script(program=program, execute=True)
|
|
134
142
|
return None
|
|
135
143
|
elif platform.system() == "Linux":
|
|
136
|
-
program = get_zellij_cmd(wd1=
|
|
144
|
+
program = get_zellij_cmd(wd1=repo_local_root, wd2=repo_remote_root)
|
|
137
145
|
write_shell_script(program=program, execute=True)
|
|
138
146
|
return None
|
|
139
147
|
else: raise NotImplementedError(f"Platform {platform.system()} not implemented.")
|
|
@@ -5,14 +5,17 @@ TODO: use typer to make clis
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from crocodile.file_management import P, Read, Struct
|
|
8
|
-
from crocodile.core import install_n_import
|
|
8
|
+
# from crocodile.core import install_n_import
|
|
9
9
|
from machineconfig.utils.utils import PROGRAM_PATH, DEFAULTS_PATH
|
|
10
10
|
from machineconfig.scripts.python.cloud_mount import get_mprocs_mount_txt
|
|
11
11
|
import argparse
|
|
12
12
|
import os
|
|
13
13
|
from typing import Optional
|
|
14
14
|
# from dataclasses import dataclass
|
|
15
|
+
# install_n_import("pydantic")
|
|
15
16
|
# from tap import Tap
|
|
17
|
+
from pydantic.dataclasses import dataclass
|
|
18
|
+
from pydantic import ConfigDict
|
|
16
19
|
|
|
17
20
|
|
|
18
21
|
ES = "^" # chosen carefully to not mean anything on any shell. `$` was a bad choice.
|
|
@@ -32,11 +35,6 @@ class ArgsDefaults:
|
|
|
32
35
|
pwd = None
|
|
33
36
|
|
|
34
37
|
|
|
35
|
-
install_n_import("pydantic")
|
|
36
|
-
from pydantic.dataclasses import dataclass # type: ignore # ruffle: ignore
|
|
37
|
-
from pydantic import ConfigDict
|
|
38
|
-
|
|
39
|
-
|
|
40
38
|
@dataclass(config=ConfigDict(extra="forbid", frozen=True))
|
|
41
39
|
class Args():
|
|
42
40
|
cloud: Optional[str] = None
|
|
@@ -8,7 +8,7 @@ import argparse
|
|
|
8
8
|
# import subprocess
|
|
9
9
|
# import platform
|
|
10
10
|
from crocodile.file_management import P, randstr
|
|
11
|
-
from machineconfig.utils.ve import get_ipython_profile, get_ve_profile
|
|
11
|
+
from machineconfig.utils.ve import get_ipython_profile, get_ve_profile, get_ve_name_and_ipython_profile
|
|
12
12
|
from machineconfig.utils.utils import PROGRAM_PATH, display_options
|
|
13
13
|
|
|
14
14
|
|
|
@@ -34,8 +34,8 @@ def get_read_data_pycode(path: str):
|
|
|
34
34
|
p = P(r\'{path}\').absolute()
|
|
35
35
|
try:
|
|
36
36
|
dat = p.readit()
|
|
37
|
-
if
|
|
38
|
-
else: print(f"
|
|
37
|
+
if isinstance(dat, dict): Struct(dat).print(as_config=True, title=p.name)
|
|
38
|
+
else: print(f"Successfully read the file {{p.name}}")
|
|
39
39
|
except Exception as e:
|
|
40
40
|
print(e)
|
|
41
41
|
|
|
@@ -93,17 +93,23 @@ def build_parser():
|
|
|
93
93
|
options = P.cwd().search("*.py", r=True).apply(str).list
|
|
94
94
|
file = display_options(msg="Choose a python file to run", options=options, fzf=True, multi=False, )
|
|
95
95
|
assert isinstance(file, str)
|
|
96
|
-
if profile is None:
|
|
96
|
+
if profile is None:
|
|
97
|
+
profile = get_ipython_profile(P(file))
|
|
97
98
|
program = P(file).read_text(encoding='utf-8')
|
|
98
99
|
|
|
99
100
|
elif args.file != "":
|
|
100
101
|
file = P(args.file.lstrip()).expanduser().absolute()
|
|
101
|
-
if profile is None:
|
|
102
|
+
if profile is None:
|
|
103
|
+
profile = get_ipython_profile(P(file))
|
|
102
104
|
program = get_read_pyfile_pycode(file, as_module=args.module, cmd=args.cmd)
|
|
103
105
|
|
|
104
106
|
elif args.read != "":
|
|
105
107
|
file = P(str(args.read).lstrip()).expanduser().absolute()
|
|
106
|
-
|
|
108
|
+
ve_name_from_file, ipy_profile_from_file = get_ve_name_and_ipython_profile(init_path=P(file))
|
|
109
|
+
# if profile is None:
|
|
110
|
+
# profile = get_ipython_profile(P(file))
|
|
111
|
+
if profile is None: profile = ipy_profile_from_file
|
|
112
|
+
if args.ve is None: args.ve = ve_name_from_file
|
|
107
113
|
program = get_read_data_pycode(str(file))
|
|
108
114
|
|
|
109
115
|
else: # just run croshell.py interactively
|
|
@@ -129,7 +135,9 @@ print_logo(logo="crocodile")
|
|
|
129
135
|
total_program = preprogram + add_print_header_pycode(str(pyfile), title=title) + program
|
|
130
136
|
|
|
131
137
|
pyfile.write_text(total_program, encoding='utf-8')
|
|
132
|
-
if profile is None:
|
|
138
|
+
if profile is None:
|
|
139
|
+
profile = get_ipython_profile(P.cwd())
|
|
140
|
+
# profile = "default"
|
|
133
141
|
|
|
134
142
|
ve = get_ve_profile(P(file)) if args.ve is None else str(args.ve)
|
|
135
143
|
|
|
@@ -140,7 +148,8 @@ print_logo(logo="crocodile")
|
|
|
140
148
|
if interpreter == "ipython": final_program += f"{interactivity} --profile {profile} --no-banner"
|
|
141
149
|
final_program += f" {str(pyfile)}"
|
|
142
150
|
print(f"🔥 sourcing ... {pyfile}")
|
|
143
|
-
|
|
151
|
+
# print(f"Running ... {final_program}")
|
|
152
|
+
PROGRAM_PATH.write_text(data=final_program)
|
|
144
153
|
|
|
145
154
|
# if platform.system() == "Windows":
|
|
146
155
|
# return subprocess.run([f"powershell", "-Command", res], shell=True, capture_output=False, text=True, check=True)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
# import subprocess
|
|
6
|
+
from tqdm import tqdm
|
|
6
7
|
from crocodile.core import List as L
|
|
7
8
|
from machineconfig.utils.utils import LIBRARY_ROOT, choose_multiple_options
|
|
8
9
|
from machineconfig.utils.installer import get_installers, Installer, install_all
|
|
@@ -15,11 +16,10 @@ WHICH: TypeAlias = Literal["AllEssentials", "EssentialsAndOthers", "SystemInstal
|
|
|
15
16
|
|
|
16
17
|
def main(which: Optional[str] = None):
|
|
17
18
|
sys = system()
|
|
18
|
-
installers = get_installers(dev=False, system=sys) + get_installers(dev=True, system=sys)
|
|
19
|
+
installers = get_installers(dev=False, system=sys) # + get_installers(dev=True, system=sys)
|
|
19
20
|
default = "AllEssentials"
|
|
20
|
-
options = ["SystemInstallers", "OtherDevApps", "EssentialsAndOthers", "PrecheckedCloudInstaller"]
|
|
21
|
-
options = [
|
|
22
|
-
options = [x.get_description() for x in installers] + options
|
|
21
|
+
options = ["SystemInstallers", "OtherDevApps", "EssentialsAndOthers", "PrecheckedCloudInstaller", default]
|
|
22
|
+
options = [x.get_description() for x in tqdm(installers, desc="Checking installed programs")] + options
|
|
23
23
|
|
|
24
24
|
if which is not None:
|
|
25
25
|
return get_program(program_name=which, options=options, installers=list(installers))
|
|
@@ -41,7 +41,10 @@ def get_program(program_name: str, options: list[str], installers: list[Installe
|
|
|
41
41
|
program = ""
|
|
42
42
|
elif program_name == "SystemInstallers":
|
|
43
43
|
if system() == "Windows": options_system = parse_apps_installer_windows(LIBRARY_ROOT.joinpath("setup_windows/apps.ps1").read_text())
|
|
44
|
-
elif system() == "Linux":
|
|
44
|
+
elif system() == "Linux":
|
|
45
|
+
options_system_1 = parse_apps_installer_linux(LIBRARY_ROOT.joinpath("setup_linux/apps_dev.sh").read_text())
|
|
46
|
+
options_system_2 = parse_apps_installer_linux(LIBRARY_ROOT.joinpath("setup_linux/apps.sh").read_text())
|
|
47
|
+
options_system = {**options_system_1, **options_system_2}
|
|
45
48
|
else: raise NotImplementedError(f"System {system()} not supported")
|
|
46
49
|
program_names = choose_multiple_options(msg="", options=sorted(list(options_system.keys())), header="CHOOSE DEV APP")
|
|
47
50
|
program = ""
|
|
@@ -51,10 +54,12 @@ def get_program(program_name: str, options: list[str], installers: list[Installe
|
|
|
51
54
|
program += "\n" + sub_program
|
|
52
55
|
elif program_name == "OtherDevApps":
|
|
53
56
|
installers = get_installers(dev=True, system=system())
|
|
54
|
-
options__: list[str] = [x.get_description() for x in installers]
|
|
57
|
+
options__: list[str] = [x.get_description() for x in tqdm(installers, desc="Checking installed programs")]
|
|
55
58
|
program_names = choose_multiple_options(msg="", options=sorted(options__) + ["all"], header="CHOOSE DEV APP")
|
|
56
59
|
if "all" in program_names: program_names = options__
|
|
57
60
|
program = ""
|
|
61
|
+
print(f"Installing:")
|
|
62
|
+
L(program_names).print()
|
|
58
63
|
for name in program_names:
|
|
59
64
|
try:
|
|
60
65
|
idx = options__.index(name)
|
|
@@ -62,6 +67,7 @@ def get_program(program_name: str, options: list[str], installers: list[Installe
|
|
|
62
67
|
print(f"{name=}")
|
|
63
68
|
print(f"{options__=}")
|
|
64
69
|
raise ve
|
|
70
|
+
print(f"Installing {name}")
|
|
65
71
|
sub_program = installers[idx].install_robust(version=None) # finish the task
|
|
66
72
|
elif program_name == "PrecheckedCloudInstaller":
|
|
67
73
|
from machineconfig.jobs.python.check_installations import PrecheckedCloudInstaller
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
|
|
2
2
|
"""
|
|
3
3
|
fire
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
4
|
|
|
7
|
-
from machineconfig.utils.utils import display_options, choose_one_option, PROGRAM_PATH, choose_ssh_host, match_file_name, sanitize_path
|
|
8
|
-
# from crocodile.run import *
|
|
9
5
|
# https://github.com/pallets/click combine with fire. Consider
|
|
10
6
|
# https://github.com/ceccopierangiolieugenio/pyTermTk for display_options build TUI
|
|
11
7
|
# https://github.com/chriskiehl/Gooey build commandline interface
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
from machineconfig.utils.utils import display_options, choose_one_option, PROGRAM_PATH, choose_ssh_host, match_file_name, sanitize_path
|
|
12
13
|
from crocodile.file_management import P, install_n_import
|
|
13
14
|
from crocodile.core import Display, randstr
|
|
14
15
|
import inspect
|
|
@@ -20,21 +21,23 @@ import argparse
|
|
|
20
21
|
|
|
21
22
|
def main() -> None:
|
|
22
23
|
parser = argparse.ArgumentParser()
|
|
23
|
-
parser.add_argument("path",
|
|
24
|
+
parser.add_argument("path", nargs='?', type=str, help="The directory containing the jobs", default=".")
|
|
24
25
|
parser.add_argument("function", nargs='?', type=str, help="Fuction to run", default=None)
|
|
25
26
|
# parser.add_argument("--function", "-f", type=str, help="The function to run", default="")
|
|
26
|
-
parser.add_argument("--ve",
|
|
27
|
-
parser.add_argument("--cmd",
|
|
28
|
-
parser.add_argument("--interactive",
|
|
29
|
-
parser.add_argument("--debug",
|
|
27
|
+
parser.add_argument("--ve", "-v", type=str, help="virtual enviroment name", default="")
|
|
28
|
+
parser.add_argument("--cmd", "-B", action="store_true", help="Create a cmd fire command to launch the the job asynchronously.")
|
|
29
|
+
parser.add_argument("--interactive", "-i", action="store_true", help="Whether to run the job interactively using IPython")
|
|
30
|
+
parser.add_argument("--debug", "-d", action="store_true", help="debug")
|
|
30
31
|
parser.add_argument("--choose_function", "-c", action="store_true", help="debug")
|
|
31
|
-
parser.add_argument("--loop",
|
|
32
|
-
parser.add_argument("--jupyter",
|
|
32
|
+
parser.add_argument("--loop", "-l", action="store_true", help="infinite recusion (runs again after completion)")
|
|
33
|
+
parser.add_argument("--jupyter", "-j", action="store_true", help="open in a jupyter notebook")
|
|
33
34
|
parser.add_argument("--submit_to_cloud", "-C", action="store_true", help="submit to cloud compute")
|
|
34
|
-
parser.add_argument("--remote",
|
|
35
|
-
parser.add_argument("--module",
|
|
36
|
-
parser.add_argument("--streamlit",
|
|
37
|
-
parser.add_argument("--history",
|
|
35
|
+
parser.add_argument("--remote", "-r", action="store_true", help="launch on a remote machine")
|
|
36
|
+
parser.add_argument("--module", "-m", action="store_true", help="launch the main file")
|
|
37
|
+
parser.add_argument("--streamlit", "-S", action="store_true", help="run as streamlit app")
|
|
38
|
+
parser.add_argument("--history", "-H", action="store_true", help="choose from history")
|
|
39
|
+
# parser.add_argument("--git_pull", "-g", action="store_true", help="Start by pulling the git repo")
|
|
40
|
+
parser.add_argument("--Nprocess", "-p", type=int, help="Number of processes to use", default=1)
|
|
38
41
|
parser.add_argument("--kw", nargs="*", default=None, help="keyword arguments to pass to the function in the form of k1 v1 k2 v2 ...")
|
|
39
42
|
|
|
40
43
|
args = parser.parse_args()
|
|
@@ -47,12 +50,9 @@ def main() -> None:
|
|
|
47
50
|
|
|
48
51
|
path_obj = sanitize_path(P(args.path))
|
|
49
52
|
if not path_obj.exists():
|
|
50
|
-
print("This pathway")
|
|
51
53
|
path_obj = match_file_name(args.path)
|
|
52
54
|
print(path_obj)
|
|
53
|
-
else:
|
|
54
|
-
print("This directory")
|
|
55
|
-
print(path_obj)
|
|
55
|
+
else: pass
|
|
56
56
|
|
|
57
57
|
if path_obj.is_dir():
|
|
58
58
|
print(f"Seaching recursively for all python file in directory `{path_obj}`")
|
|
@@ -68,10 +68,9 @@ def main() -> None:
|
|
|
68
68
|
|
|
69
69
|
if choice_file.suffix in [".ps1", ".sh"]:
|
|
70
70
|
PROGRAM_PATH.write_text(f". {choice_file}")
|
|
71
|
-
return
|
|
71
|
+
return None
|
|
72
72
|
|
|
73
73
|
if args.choose_function or args.submit_to_cloud:
|
|
74
|
-
|
|
75
74
|
options, func_args = parse_pyfile(file_path=str(choice_file))
|
|
76
75
|
choice_function_tmp = display_options(msg="Choose a function to run", options=options, fzf=True, multi=False)
|
|
77
76
|
assert isinstance(choice_function_tmp, str), f"choice_function must be a string. Got {type(choice_function_tmp)}"
|
|
@@ -83,13 +82,21 @@ def main() -> None:
|
|
|
83
82
|
if len(choice_function_args) > 0 and len(kwargs) == 0:
|
|
84
83
|
for item in choice_function_args:
|
|
85
84
|
kwargs[item.name] = input(f"Please enter a value for argument `{item.name}` (type = {item.type}) (default = {item.default}) : ") or item.default
|
|
86
|
-
else:
|
|
85
|
+
else:
|
|
86
|
+
choice_function = args.function
|
|
87
87
|
|
|
88
88
|
if args.ve == "":
|
|
89
89
|
from machineconfig.utils.ve import get_ve_profile # if file name is passed explicitly, then, user probably launched it from cwd different to repo root, so activate_ve can't infer ve from .ve_path, so we attempt to do that manually here
|
|
90
90
|
args.ve = get_ve_profile(choice_file)
|
|
91
91
|
|
|
92
|
-
if args.streamlit:
|
|
92
|
+
if args.streamlit:
|
|
93
|
+
import socket
|
|
94
|
+
try: local_ip_v4 = socket.gethostbyname(socket.gethostname() + ".local") # without .local, in linux machines, '/etc/hosts' file content, you have an IP address mapping with '127.0.1.1' to your hostname
|
|
95
|
+
except Exception:
|
|
96
|
+
print(f"Warning: Could not get local_ip_v4. This is probably because you are running a WSL instance") # TODO find a way to get the local_ip_v4 in WSL
|
|
97
|
+
local_ip_v4 = socket.gethostbyname(socket.gethostname())
|
|
98
|
+
print(f"🚀 Streamlit app is running at: http://{local_ip_v4}:8501")
|
|
99
|
+
exe = "streamlit run --server.address 0.0.0.0 --server.headless true"
|
|
93
100
|
elif args.interactive is False: exe = "python"
|
|
94
101
|
elif args.jupyter: exe = "jupyter-lab"
|
|
95
102
|
else:
|
|
@@ -97,12 +104,13 @@ def main() -> None:
|
|
|
97
104
|
exe = f"ipython -i --no-banner --profile {get_ipython_profile(choice_file)} "
|
|
98
105
|
|
|
99
106
|
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.
|
|
107
|
+
import_line = get_import_module_code(str(choice_file))
|
|
100
108
|
txt: str = f"""
|
|
101
109
|
try:
|
|
102
|
-
{
|
|
110
|
+
{import_line}
|
|
103
111
|
except (ImportError, ModuleNotFoundError) as ex:
|
|
104
|
-
print(fr"Failed to import {choice_file} the proper way. {{ex}} ")
|
|
105
|
-
print(fr"
|
|
112
|
+
print(fr"Failed to import `{choice_file}` the proper way. {{ex}} ")
|
|
113
|
+
print(fr"Importing with an ad-hoc `$PATH` manipulation. DO NOT pickle any files in this session as there is no gaurantee of correct deserialization.")
|
|
106
114
|
import sys
|
|
107
115
|
sys.path.append(r'{P(choice_file).parent}')
|
|
108
116
|
from {P(choice_file).stem} import *
|
|
@@ -110,11 +118,17 @@ except (ImportError, ModuleNotFoundError) as ex:
|
|
|
110
118
|
"""
|
|
111
119
|
if choice_function is not None:
|
|
112
120
|
txt = txt + f"""
|
|
113
|
-
{choice_function}({('**' + str(kwargs)) if kwargs else ''})
|
|
121
|
+
res = {choice_function}({('**' + str(kwargs)) if kwargs else ''})
|
|
114
122
|
"""
|
|
115
123
|
txt = f"""
|
|
116
|
-
|
|
117
|
-
|
|
124
|
+
try:
|
|
125
|
+
from rich.panel import Panel
|
|
126
|
+
from rich.console import Console
|
|
127
|
+
from rich.syntax import Syntax
|
|
128
|
+
console = Console()
|
|
129
|
+
console.print(Panel(Syntax(code=r'''{txt}''', lexer='python'), title='Import Script'), style="bold red")
|
|
130
|
+
except ImportError as _ex:
|
|
131
|
+
print(r'''{txt}''')
|
|
118
132
|
""" + txt
|
|
119
133
|
choice_file = P.tmp().joinpath(f'tmp_scripts/python/{P(choice_file).parent.name}_{P(choice_file).stem}_{randstr()}.py').create(parents_only=True).write_text(txt)
|
|
120
134
|
|
|
@@ -131,15 +145,19 @@ print_code(code=r'''{txt}''', lexer='python', desc='Import Script')
|
|
|
131
145
|
if not kwargs: # empty dict
|
|
132
146
|
kwargs_str = ''
|
|
133
147
|
else:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
148
|
+
if len(kwargs) == 1:
|
|
149
|
+
kwargs_str = f""" --{list(kwargs.keys())[0]} {list(kwargs.values())[0]} """
|
|
150
|
+
else:
|
|
151
|
+
# print(f"len(kwargs) = {len(kwargs)}")
|
|
152
|
+
tmp_list: list[str] = []
|
|
153
|
+
for k, v in kwargs.items():
|
|
154
|
+
if v is not None:
|
|
155
|
+
item = f'"{k}": "{v}"'
|
|
156
|
+
else:
|
|
157
|
+
item = f'"{k}": None'
|
|
158
|
+
tmp_list.append(item)
|
|
159
|
+
tmp__ = ", ".join(tmp_list)
|
|
160
|
+
kwargs_str = "'{" + tmp__ + "}'"
|
|
143
161
|
command = f"{exe} -m fire {choice_file} {choice_function} {kwargs_str}"
|
|
144
162
|
# else:
|
|
145
163
|
# print(f"{kwargs=}")
|
|
@@ -152,19 +170,22 @@ print_code(code=r'''{txt}''', lexer='python', desc='Import Script')
|
|
|
152
170
|
else:
|
|
153
171
|
if not args.cmd:
|
|
154
172
|
# for .streamlit config to work, it needs to be in the current directory.
|
|
155
|
-
command = f"cd {choice_file.parent}
|
|
173
|
+
command = f"cd {choice_file.parent}\n\n{exe} {choice_file.name}\n\ncd {P.cwd()}"
|
|
156
174
|
else:
|
|
157
175
|
command = rf""" cd /d {choice_file.parent} & {exe} {choice_file.name} """
|
|
158
|
-
# command = f"cd {choice_file.parent}
|
|
176
|
+
# command = f"cd {choice_file.parent}\n\n{exe} {choice_file.name}\n\ncd {P.cwd()}"
|
|
159
177
|
|
|
160
178
|
# this installs in ve env, which is not execution env
|
|
161
179
|
# if "ipdb" in command: install_n_import("ipdb")
|
|
162
180
|
# if "pudb" in command: install_n_import("pudb")
|
|
163
181
|
|
|
164
182
|
if not args.cmd:
|
|
165
|
-
if "ipdb" in command: command = f"pip install ipdb
|
|
166
|
-
if "pudb" in command: command = f"pip install pudb
|
|
167
|
-
|
|
183
|
+
if "ipdb" in command: command = f"pip install ipdb\n\n{command}"
|
|
184
|
+
if "pudb" in command: command = f"pip install pudb\n\n{command}"
|
|
185
|
+
if platform.system() == "Windows":
|
|
186
|
+
command = f". activate_ve {args.ve}\n\n{command}"
|
|
187
|
+
else:
|
|
188
|
+
command = f". ~/scripts/activate_ve {args.ve}\n\n{command}"
|
|
168
189
|
else:
|
|
169
190
|
# CMD equivalent
|
|
170
191
|
if "ipdb" in command: command = f"pip install ipdb & {command}"
|
|
@@ -183,7 +204,18 @@ python -m crocodile.cluster.templates.cli_click --file {choice_file} """
|
|
|
183
204
|
if args.loop:
|
|
184
205
|
command = command + f"\n" + f". {PROGRAM_PATH}"
|
|
185
206
|
|
|
207
|
+
if args.Nprocess > 1:
|
|
208
|
+
lines = [f""" zellij action new-tab --name nProcess{randstr(2)}"""]
|
|
209
|
+
command = command.replace(". activate_ve", ". ~/scripts/activate_ve")
|
|
210
|
+
for an_arg in range(args.Nprocess):
|
|
211
|
+
sub_command = f"{command} --idx={an_arg} --idx_max={args.Nprocess}"
|
|
212
|
+
sub_command_path = P.tmpfile(suffix=".sh").write_text(sub_command)
|
|
213
|
+
lines.append(f"""zellij action new-pane -- bash {sub_command_path} """)
|
|
214
|
+
lines.append("sleep 1") # python tends to freeze if you launch instances within 1 microsecond of each other
|
|
215
|
+
command = "\n".join(lines)
|
|
216
|
+
|
|
186
217
|
# TODO: send this command to terminal history. In powershell & bash there is no way to do it with a command other than goiing to history file. In Mcfly there is a way but its linux only tool. # if platform.system() == "Windows": command = f" ({command}) | Add-History -PassThru "
|
|
218
|
+
# mcfly add --exit 0 command
|
|
187
219
|
print(f"🔥 command:\n{command}\n\n")
|
|
188
220
|
# if platform.system() == "Linux":
|
|
189
221
|
# command = "timeout 1s aafire -driver slang\nclear\n" + command
|
|
@@ -235,11 +267,11 @@ def parse_pyfile(file_path: str):
|
|
|
235
267
|
return options, func_args
|
|
236
268
|
|
|
237
269
|
|
|
238
|
-
def
|
|
270
|
+
def get_attrs_recursively(obj: Any):
|
|
239
271
|
if hasattr(obj, '__dict__'):
|
|
240
272
|
res = {}
|
|
241
273
|
for k, v in obj.__dict__.items():
|
|
242
|
-
res[k] =
|
|
274
|
+
res[k] = get_attrs_recursively(v)
|
|
243
275
|
return res
|
|
244
276
|
return obj
|
|
245
277
|
|
|
@@ -281,25 +313,32 @@ def run_on_remote(func_file: str, args: argparse.Namespace):
|
|
|
281
313
|
m.run()
|
|
282
314
|
|
|
283
315
|
|
|
284
|
-
def
|
|
316
|
+
def find_repo_root_path(start_path: str) -> Optional[str]:
|
|
285
317
|
root_files = ['setup.py', 'pyproject.toml', '.git']
|
|
286
|
-
path = start_path
|
|
287
|
-
|
|
318
|
+
path: str = start_path
|
|
319
|
+
trials = 0
|
|
320
|
+
root_path = os.path.abspath(os.sep)
|
|
321
|
+
while path != root_path and trials < 20:
|
|
288
322
|
for root_file in root_files:
|
|
289
323
|
if os.path.exists(os.path.join(path, root_file)):
|
|
324
|
+
print(f"Found repo root path: {path}")
|
|
290
325
|
return path
|
|
291
326
|
path = os.path.dirname(path)
|
|
327
|
+
trials += 1
|
|
292
328
|
return None
|
|
293
329
|
|
|
294
330
|
|
|
295
331
|
def get_import_module_code(module_path: str):
|
|
296
|
-
root_path =
|
|
332
|
+
root_path = find_repo_root_path(module_path)
|
|
297
333
|
if root_path is None: # just make a desperate attempt to import it
|
|
298
334
|
module_name = module_path.lstrip(os.sep).replace(os.sep, '.').replace('.py', '')
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
335
|
+
else:
|
|
336
|
+
relative_path = module_path.replace(root_path, '')
|
|
337
|
+
module_name = relative_path.lstrip(os.sep).replace(os.sep, '.').replace('.py', '')
|
|
338
|
+
module_name = module_name.replace("src.", "").replace("myresources.", "").replace("resources.", "").replace("source.", "").replace("resources.", "").replace("source.", "").replace("src.", "").replace("myresources.", "").replace("resources.", "").replace("source.", "").replace("src.", "").replace("myresources.", "").replace("resources.", "").replace("source.", "").replace("src.", "").replace("myresources.", "").replace("resources.", "").replace("source.", "").replace("src.", "").replace("myresources.", "").replace("resources.", "").replace("source.", "").replace("src.", "").replace("myresources.", "").replace("resources.", "").replace("source.", "").replace("src.", "").replace("myresources.", "").replace("resources.", "").replace("source.", "").replace("src.", "").replace("resources.", "").replace("source.", "")
|
|
339
|
+
if any(char in module_name for char in "- :/\\"):
|
|
340
|
+
module_name = "IncorrectModuleName"
|
|
341
|
+
# TODO: use py_compile to check if the statement is valid code to avoid syntax errors that can't be caught.
|
|
303
342
|
return f"from {module_name} import *"
|
|
304
343
|
|
|
305
344
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
TODO: add support for cases in which source or target has non 22 default port number and is defineda as user@host:port:path which makes 2 colons in the string.
|
|
5
5
|
Currently, the only way to work around this is to predifine the host in ~/.ssh/config and use the alias in the source or target which is inconvenient when dealing with newly setup machines.
|
|
6
|
+
|
|
6
7
|
"""
|
|
7
8
|
|
|
8
9
|
import argparse
|
|
@@ -19,6 +20,7 @@ def main():
|
|
|
19
20
|
# FLAGS
|
|
20
21
|
parser.add_argument("--recursive", "-r", help="Send recursively.", action="store_true") # default is False
|
|
21
22
|
parser.add_argument("--zipFirst", "-z", help="Zip before sending.", action="store_true") # default is False
|
|
23
|
+
parser.add_argument("--cloud", "-c", help="Transfer through the cloud.", action="store_true") # default is False
|
|
22
24
|
|
|
23
25
|
args = parser.parse_args()
|
|
24
26
|
|
|
@@ -54,6 +56,7 @@ def main():
|
|
|
54
56
|
raise ValueError("Either source or target must be a remote path (i.e. machine:path)")
|
|
55
57
|
|
|
56
58
|
Struct({"source": str(source), "target": str(target), "machine": machine}).print(as_config=True, title="CLI Resolution")
|
|
59
|
+
|
|
57
60
|
from paramiko.ssh_exception import AuthenticationException # type: ignore
|
|
58
61
|
try:
|
|
59
62
|
ssh = SSH(rf'{machine}')
|
|
@@ -64,14 +67,21 @@ def main():
|
|
|
64
67
|
pwd = getpass.getpass()
|
|
65
68
|
ssh = SSH(rf'{machine}', pwd=pwd)
|
|
66
69
|
|
|
67
|
-
if
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
if args.cloud:
|
|
71
|
+
print("Uploading from remote to cloud ...")
|
|
72
|
+
ssh.run(f"cloud_copy {source} :^", desc="Uploading from remote to the cloud.").print()
|
|
73
|
+
print("Downloading from cloud to local ...")
|
|
74
|
+
ssh.run_locally(f"cloud_copy :^ {target}").print()
|
|
75
|
+
received_file = P(target) # type: ignore
|
|
71
76
|
else:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
if source_is_remote:
|
|
78
|
+
assert source is not None, "source must be a remote path (i.e. machine:path)"
|
|
79
|
+
print(f"Running: received_file = ssh.copy_to_here(source=r'{source}', target=r'{target}', z={args.zipFirst}, r={args.recursive})")
|
|
80
|
+
received_file = ssh.copy_to_here(source=source, target=target, z=args.zipFirst, r=args.recursive)
|
|
81
|
+
else:
|
|
82
|
+
assert source is not None, "target must be a remote path (i.e. machine:path)"
|
|
83
|
+
print(f"Running: received_file = ssh.copy_from_here(source=r'{source}', target=r'{target}', z={args.zipFirst}, r={args.recursive})")
|
|
84
|
+
received_file = ssh.copy_from_here(source=source, target=target, z=args.zipFirst, r=args.recursive)
|
|
75
85
|
# ssh.print_summary()
|
|
76
86
|
# if P(args.file).is_dir(): print(f"Use: cd {repr(P(args.file).expanduser())}")
|
|
77
87
|
if source_is_remote and isinstance(received_file, P):
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
"""Repos
|
|
3
|
+
|
|
4
|
+
# TODO use gh api user --jq '.login' to get the username and use it to clone the repos.
|
|
5
|
+
in the event that username@github.com is not mentioned in the remote url.
|
|
6
|
+
|
|
3
7
|
"""
|
|
4
8
|
|
|
5
9
|
from rich import print as pprint
|
|
@@ -168,7 +172,7 @@ def install_repos(specs_path: str, clone: bool = True, checkout_to_recorded_comm
|
|
|
168
172
|
if preferred_remote is not None:
|
|
169
173
|
if preferred_remote in repo["remotes"]:
|
|
170
174
|
remote_name = preferred_remote
|
|
171
|
-
remote_url
|
|
175
|
+
remote_url = repo["remotes"][preferred_remote]
|
|
172
176
|
else:
|
|
173
177
|
print(f"⚠️ `{preferred_remote=}` not found in {repo['remotes']}.")
|
|
174
178
|
# preferred_remote = None
|
|
@@ -9,7 +9,7 @@ from typing import Literal
|
|
|
9
9
|
|
|
10
10
|
COLOR_SCHEMES = ["Campbell", "Campbell Powershell", "Solarized Dark", "Ubuntu-ColorScheme", "Retro"]
|
|
11
11
|
THEMES_ITER = cycle(COLOR_SCHEMES)
|
|
12
|
-
INIT_COMMANDS = ["ls", "lf", "cpufetch", "
|
|
12
|
+
INIT_COMMANDS = ["ls", "lf", "cpufetch", "fastfetch", "btm"]
|
|
13
13
|
INIT_COMMANDS_ITER = cycle(INIT_COMMANDS)
|
|
14
14
|
SIZE_ITER = cycle([0.6, 0.4, 0.3])
|
|
15
15
|
ORIENTATION = ["vertical", "horizontal"]
|