machineconfig 1.7__py3-none-any.whl → 1.8__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 +2 -2
- machineconfig/jobs/python/check_installations.py +37 -31
- machineconfig/jobs/python/create_bootable_media.py +4 -4
- machineconfig/jobs/python/create_zellij_template.py +3 -2
- machineconfig/jobs/python/python_cargo_build_share.py +14 -9
- machineconfig/jobs/python/python_ve_symlink.py +6 -6
- machineconfig/jobs/{python_linux_installers/dev → script_installer}/azure_data_studio.py +6 -5
- machineconfig/jobs/{python_windows_installers/dev → script_installer}/bypass_paywall.py +5 -4
- machineconfig/jobs/script_installer/code.py +34 -0
- machineconfig/jobs/{python_linux_installers/dev → script_installer}/docker_desktop.py +2 -2
- machineconfig/jobs/script_installer/ngrok.py +29 -0
- machineconfig/jobs/script_installer/skim.py +21 -0
- machineconfig/jobs/script_installer/wezterm.py +34 -0
- machineconfig/profile/create.py +8 -6
- machineconfig/profile/shell.py +15 -13
- machineconfig/scripts/python/cloud_copy.py +14 -13
- machineconfig/scripts/python/cloud_mount.py +27 -11
- machineconfig/scripts/python/cloud_repo_sync.py +32 -14
- machineconfig/scripts/python/cloud_sync.py +9 -9
- machineconfig/scripts/python/croshell.py +3 -3
- machineconfig/scripts/python/devops.py +22 -6
- machineconfig/scripts/python/devops_add_identity.py +7 -6
- machineconfig/scripts/python/devops_add_ssh_key.py +10 -9
- machineconfig/scripts/python/devops_backup_retrieve.py +5 -5
- machineconfig/scripts/python/devops_devapps_install.py +13 -14
- machineconfig/scripts/python/devops_update_repos.py +5 -4
- machineconfig/scripts/python/dotfile.py +8 -4
- machineconfig/scripts/python/fire_jobs.py +95 -24
- machineconfig/scripts/python/ftpx.py +1 -1
- machineconfig/scripts/python/mount_nfs.py +13 -10
- machineconfig/scripts/python/mount_nw_drive.py +4 -3
- machineconfig/scripts/python/mount_ssh.py +8 -5
- machineconfig/scripts/python/repos.py +21 -20
- machineconfig/scripts/python/snapshot.py +2 -2
- machineconfig/scripts/python/start_slidev.py +104 -0
- machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +20 -34
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +11 -12
- machineconfig/utils/installer.py +96 -204
- machineconfig/utils/scheduling.py +1 -1
- machineconfig/utils/utils.py +102 -51
- machineconfig/utils/ve.py +96 -13
- {machineconfig-1.7.dist-info → machineconfig-1.8.dist-info}/METADATA +8 -8
- machineconfig-1.8.dist-info/RECORD +70 -0
- machineconfig/jobs/python_generic_installers/archive/gopass.py +0 -18
- machineconfig/jobs/python_generic_installers/archive/nvim.py +0 -20
- machineconfig/jobs/python_generic_installers/archive/opencommit.py +0 -25
- machineconfig/jobs/python_generic_installers/archive/strongbox.py +0 -33
- machineconfig/jobs/python_generic_installers/dev/__init__.py +0 -0
- machineconfig/jobs/python_linux_installers/archive/__init__.py +0 -0
- machineconfig/jobs/python_linux_installers/archive/bandwhich.py +0 -14
- machineconfig/jobs/python_linux_installers/archive/ranger.py +0 -19
- machineconfig/jobs/python_linux_installers/dev/bytehound.py +0 -20
- machineconfig/jobs/python_linux_installers/dev/nnn.py +0 -22
- machineconfig/jobs/python_windows_installers/archive/ntop.py +0 -21
- machineconfig/jobs/python_windows_installers/dev/obs_background_removal_plugin.py +0 -22
- machineconfig/scripts/python/choose_ohmybash_theme.py +0 -31
- machineconfig/scripts/python/choose_ohmyposh_theme.py +0 -57
- machineconfig/utils/pandas_type.py +0 -37
- machineconfig/utils/to_exe.py +0 -7
- machineconfig-1.7.dist-info/RECORD +0 -81
- /machineconfig/jobs/{python_generic_installers/archive → script_installer}/__init__.py +0 -0
- {machineconfig-1.7.dist-info → machineconfig-1.8.dist-info}/WHEEL +0 -0
- {machineconfig-1.7.dist-info → machineconfig-1.8.dist-info}/top_level.txt +0 -0
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
fire
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
from machineconfig.utils.utils import display_options, PROGRAM_PATH, choose_ssh_host, match_file_name, sanitize_path
|
|
6
|
+
|
|
7
|
+
from machineconfig.utils.utils import display_options, choose_one_option, PROGRAM_PATH, choose_ssh_host, match_file_name, sanitize_path
|
|
8
8
|
# from crocodile.run import *
|
|
9
9
|
# https://github.com/pallets/click combine with fire. Consider
|
|
10
10
|
# https://github.com/ceccopierangiolieugenio/pyTermTk for display_options build TUI
|
|
11
11
|
# https://github.com/chriskiehl/Gooey build commandline interface
|
|
12
|
+
from crocodile.file_management import P, install_n_import
|
|
13
|
+
from crocodile.core import Display, randstr
|
|
12
14
|
import inspect
|
|
13
15
|
import platform
|
|
14
16
|
import os
|
|
@@ -16,7 +18,7 @@ from typing import Callable, Any, Optional
|
|
|
16
18
|
import argparse
|
|
17
19
|
|
|
18
20
|
|
|
19
|
-
def main():
|
|
21
|
+
def main() -> None:
|
|
20
22
|
parser = argparse.ArgumentParser()
|
|
21
23
|
parser.add_argument("path", nargs='?', type=str, help="The directory containing the jobs", default=".")
|
|
22
24
|
parser.add_argument("function", nargs='?', type=str, help="Fuction to run", default=None)
|
|
@@ -27,6 +29,7 @@ def main():
|
|
|
27
29
|
parser.add_argument("--debug", "-d", action="store_true", help="debug")
|
|
28
30
|
parser.add_argument("--choose_function", "-c", action="store_true", help="debug")
|
|
29
31
|
parser.add_argument("--loop", "-l", action="store_true", help="infinite recusion (runs again after completion)")
|
|
32
|
+
parser.add_argument("--jupyter", "-j", action="store_true", help="open in a jupyter notebook")
|
|
30
33
|
parser.add_argument("--submit_to_cloud", "-C", action="store_true", help="submit to cloud compute")
|
|
31
34
|
parser.add_argument("--remote", "-r", action="store_true", help="launch on a remote machine")
|
|
32
35
|
parser.add_argument("--module", "-m", action="store_true", help="launch the main file")
|
|
@@ -42,8 +45,14 @@ def main():
|
|
|
42
45
|
else:
|
|
43
46
|
kwargs = {}
|
|
44
47
|
|
|
45
|
-
path_obj = sanitize_path(
|
|
46
|
-
if not path_obj.exists():
|
|
48
|
+
path_obj = sanitize_path(P(args.path))
|
|
49
|
+
if not path_obj.exists():
|
|
50
|
+
print("This pathway")
|
|
51
|
+
path_obj = match_file_name(args.path)
|
|
52
|
+
print(path_obj)
|
|
53
|
+
else:
|
|
54
|
+
print("This directory")
|
|
55
|
+
print(path_obj)
|
|
47
56
|
|
|
48
57
|
if path_obj.is_dir():
|
|
49
58
|
print(f"Seaching recursively for all python file in directory `{path_obj}`")
|
|
@@ -52,9 +61,8 @@ def main():
|
|
|
52
61
|
sh_files = path_obj.search(pattern="*.sh", r=True).list
|
|
53
62
|
files = py_files + ps_files + sh_files
|
|
54
63
|
|
|
55
|
-
choice_file =
|
|
56
|
-
|
|
57
|
-
choice_file = tb.P(choice_file)
|
|
64
|
+
choice_file = choose_one_option(options=files, fzf=True)
|
|
65
|
+
choice_file = P(choice_file)
|
|
58
66
|
else:
|
|
59
67
|
choice_file = path_obj
|
|
60
68
|
|
|
@@ -81,8 +89,9 @@ def main():
|
|
|
81
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
|
|
82
90
|
args.ve = get_ve_profile(choice_file)
|
|
83
91
|
|
|
84
|
-
if args.streamlit: exe = "streamlit run"
|
|
92
|
+
if args.streamlit: exe = "streamlit run --server.address 0.0.0.0 "
|
|
85
93
|
elif args.interactive is False: exe = "python"
|
|
94
|
+
elif args.jupyter: exe = "jupyter-lab"
|
|
86
95
|
else:
|
|
87
96
|
from machineconfig.utils.ve import get_ipython_profile
|
|
88
97
|
exe = f"ipython -i --no-banner --profile {get_ipython_profile(choice_file)} "
|
|
@@ -95,8 +104,8 @@ except (ImportError, ModuleNotFoundError) as ex:
|
|
|
95
104
|
print(fr"Failed to import {choice_file} the proper way. {{ex}} ")
|
|
96
105
|
print(fr"The way below is rather hacky and can cause issues in pickling.")
|
|
97
106
|
import sys
|
|
98
|
-
sys.path.append(r'{
|
|
99
|
-
from {
|
|
107
|
+
sys.path.append(r'{P(choice_file).parent}')
|
|
108
|
+
from {P(choice_file).stem} import *
|
|
100
109
|
|
|
101
110
|
"""
|
|
102
111
|
if choice_function is not None:
|
|
@@ -105,9 +114,9 @@ except (ImportError, ModuleNotFoundError) as ex:
|
|
|
105
114
|
"""
|
|
106
115
|
txt = f"""
|
|
107
116
|
from machineconfig.utils.utils import print_code
|
|
108
|
-
print_code(code=r'''{txt}''', lexer='python', desc='
|
|
117
|
+
print_code(code=r'''{txt}''', lexer='python', desc='Import Script')
|
|
109
118
|
""" + txt
|
|
110
|
-
choice_file =
|
|
119
|
+
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)
|
|
111
120
|
|
|
112
121
|
# determining basic command structure: putting together exe & choice_file & choice_function & pdb
|
|
113
122
|
if args.debug:
|
|
@@ -118,8 +127,20 @@ print_code(code=r'''{txt}''', lexer='python', desc='Imported Script')
|
|
|
118
127
|
else: raise NotImplementedError(f"Platform {platform.system()} not supported.")
|
|
119
128
|
elif choice_function is not None and not args.module: # if args.module, then kwargs are handled in the impot script, no need to pass them in fire command.
|
|
120
129
|
# https://google.github.io/python-fire/guide/
|
|
121
|
-
|
|
122
|
-
|
|
130
|
+
# https://github.com/google/python-fire/blob/master/docs/guide.md#argument-parsing
|
|
131
|
+
if not kwargs: # empty dict
|
|
132
|
+
kwargs_str = ''
|
|
133
|
+
else:
|
|
134
|
+
tmp_list: list[str] = []
|
|
135
|
+
for k, v in kwargs.items():
|
|
136
|
+
if v is not None:
|
|
137
|
+
item = f'"{k}": "{v}"'
|
|
138
|
+
else:
|
|
139
|
+
item = f'"{k}": None'
|
|
140
|
+
tmp_list.append(item)
|
|
141
|
+
tmp__ = ", ".join(tmp_list)
|
|
142
|
+
kwargs_str = "'{" + tmp__ + "}'"
|
|
143
|
+
command = f"{exe} -m fire {choice_file} {choice_function} {kwargs_str}"
|
|
123
144
|
# else:
|
|
124
145
|
# print(f"{kwargs=}")
|
|
125
146
|
# print(f"{choice_function_args=}")
|
|
@@ -131,16 +152,23 @@ print_code(code=r'''{txt}''', lexer='python', desc='Imported Script')
|
|
|
131
152
|
else:
|
|
132
153
|
if not args.cmd:
|
|
133
154
|
# for .streamlit config to work, it needs to be in the current directory.
|
|
134
|
-
command = f"cd {choice_file.parent}; {exe} {choice_file.name}; cd {
|
|
135
|
-
else:
|
|
136
|
-
|
|
155
|
+
command = f"cd {choice_file.parent}; {exe} {choice_file.name}; cd {P.cwd()}"
|
|
156
|
+
else:
|
|
157
|
+
command = rf""" cd /d {choice_file.parent} & {exe} {choice_file.name} """
|
|
158
|
+
# command = f"cd {choice_file.parent}; {exe} {choice_file.name}; cd {P.cwd()}"
|
|
137
159
|
|
|
138
|
-
|
|
139
|
-
if "
|
|
160
|
+
# this installs in ve env, which is not execution env
|
|
161
|
+
# if "ipdb" in command: install_n_import("ipdb")
|
|
162
|
+
# if "pudb" in command: install_n_import("pudb")
|
|
140
163
|
|
|
141
164
|
if not args.cmd:
|
|
165
|
+
if "ipdb" in command: command = f"pip install ipdb; {command}"
|
|
166
|
+
if "pudb" in command: command = f"pip install pudb; {command}"
|
|
142
167
|
command = f". activate_ve {args.ve}; {command}"
|
|
143
168
|
else:
|
|
169
|
+
# CMD equivalent
|
|
170
|
+
if "ipdb" in command: command = f"pip install ipdb & {command}"
|
|
171
|
+
if "pudb" in command: command = f"pip install pudb & {command}"
|
|
144
172
|
command = fr"""start cmd -Argument "/k %USERPROFILE%\venvs\{args.ve}\Scripts\activate.bat & {command} " """ # this works from powershell
|
|
145
173
|
# this works from cmd # command = fr""" start cmd /k "%USERPROFILE%\venvs\{args.ve}\Scripts\activate.bat & {command} " """ # because start in cmd is different from start in powershell (in powershell it is short for Start-Process)
|
|
146
174
|
|
|
@@ -149,7 +177,7 @@ print_code(code=r'''{txt}''', lexer='python', desc='Imported Script')
|
|
|
149
177
|
. activate_ve {args.ve}
|
|
150
178
|
python -m crocodile.cluster.templates.cli_click --file {choice_file} """
|
|
151
179
|
if choice_function is not None: command += f"--function {choice_function} "
|
|
152
|
-
try:
|
|
180
|
+
try: install_n_import("clipboard").copy(command)
|
|
153
181
|
except Exception as ex: print(f"Failed to copy command to clipboard. {ex}")
|
|
154
182
|
|
|
155
183
|
if args.loop:
|
|
@@ -169,14 +197,14 @@ def parse_pyfile(file_path: str):
|
|
|
169
197
|
func_args: list[list[args_spec]] = [[]] # this firt prepopulated dict is for the option 'RUN AS MAIN' which has no args
|
|
170
198
|
|
|
171
199
|
import ast
|
|
172
|
-
parsed_ast = ast.parse(
|
|
200
|
+
parsed_ast = ast.parse(P(file_path).read_text(encoding='utf-8'))
|
|
173
201
|
functions = [
|
|
174
202
|
node
|
|
175
203
|
for node in ast.walk(parsed_ast)
|
|
176
204
|
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
|
|
177
205
|
]
|
|
178
206
|
module__doc__ = ast.get_docstring(parsed_ast)
|
|
179
|
-
main_option = f"RUN AS MAIN -- {
|
|
207
|
+
main_option = f"RUN AS MAIN -- {Display.get_repr(module__doc__, limit=150) if module__doc__ is not None else 'NoDocs'}"
|
|
180
208
|
options = [main_option]
|
|
181
209
|
for function in functions:
|
|
182
210
|
if function.name.startswith('__') and function.name.endswith('__'): continue
|
|
@@ -192,7 +220,7 @@ def parse_pyfile(file_path: str):
|
|
|
192
220
|
except KeyError as ke:
|
|
193
221
|
# type_ = arg.annotation.__name__
|
|
194
222
|
# print(f"Failed to get type for {arg.annotation}. {ke}")
|
|
195
|
-
#
|
|
223
|
+
# Struct(get_attrs(arg.annotation)).print(as_yaml=True)
|
|
196
224
|
type_ = "Any" # e.g. a callable object
|
|
197
225
|
_ = ke
|
|
198
226
|
# raise ke
|
|
@@ -275,6 +303,49 @@ def get_import_module_code(module_path: str):
|
|
|
275
303
|
return f"from {module_name} import *"
|
|
276
304
|
|
|
277
305
|
|
|
306
|
+
def get_jupyter_notebook(python_code: str):
|
|
307
|
+
template = """
|
|
308
|
+
{
|
|
309
|
+
"cells": [
|
|
310
|
+
{
|
|
311
|
+
"cell_type": "code",
|
|
312
|
+
"execution_count": 1,
|
|
313
|
+
"id": "7412902a-3074-475b-9820-71b82e670a2a",
|
|
314
|
+
"metadata": {},
|
|
315
|
+
"outputs": [],
|
|
316
|
+
"source": [
|
|
317
|
+
"\n",
|
|
318
|
+
"import math"
|
|
319
|
+
]
|
|
320
|
+
}
|
|
321
|
+
],
|
|
322
|
+
"metadata": {
|
|
323
|
+
"kernelspec": {
|
|
324
|
+
"display_name": "Python 3 (ipykernel)",
|
|
325
|
+
"language": "python",
|
|
326
|
+
"name": "python3"
|
|
327
|
+
},
|
|
328
|
+
"language_info": {
|
|
329
|
+
"codemirror_mode": {
|
|
330
|
+
"name": "ipython",
|
|
331
|
+
"version": 3
|
|
332
|
+
},
|
|
333
|
+
"file_extension": ".py",
|
|
334
|
+
"mimetype": "text/x-python",
|
|
335
|
+
"name": "python",
|
|
336
|
+
"nbconvert_exporter": "python",
|
|
337
|
+
"pygments_lexer": "ipython3",
|
|
338
|
+
"version": "3.11.7"
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
"nbformat": 4,
|
|
342
|
+
"nbformat_minor": 5
|
|
343
|
+
}
|
|
344
|
+
"""
|
|
345
|
+
template.replace('"import math"', python_code)
|
|
346
|
+
return template
|
|
347
|
+
|
|
348
|
+
|
|
278
349
|
if __name__ == '__main__':
|
|
279
350
|
# options, func_args = parse_pyfile(file_path="C:/Users/aalsaf01/code/crocodile/myresources/crocodile/core.py")
|
|
280
351
|
main()
|
|
@@ -74,7 +74,7 @@ def main():
|
|
|
74
74
|
received_file = ssh.copy_from_here(source=source, target=target, z=args.zipFirst, r=args.recursive)
|
|
75
75
|
# ssh.print_summary()
|
|
76
76
|
# if P(args.file).is_dir(): print(f"Use: cd {repr(P(args.file).expanduser())}")
|
|
77
|
-
if isinstance(received_file, P):
|
|
77
|
+
if source_is_remote and isinstance(received_file, P):
|
|
78
78
|
print(f"Received: {repr(received_file.parent), repr(received_file)}")
|
|
79
79
|
|
|
80
80
|
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
"""NFS mounting script
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
from crocodile.file_management import P
|
|
7
|
+
from crocodile.meta import SSH, Terminal
|
|
8
|
+
from crocodile.core import List as L
|
|
6
9
|
from machineconfig.utils.utils import display_options, PROGRAM_PATH, choose_ssh_host
|
|
7
10
|
import platform
|
|
8
11
|
|
|
@@ -13,22 +16,22 @@ def main():
|
|
|
13
16
|
if share_info == "":
|
|
14
17
|
tmp = choose_ssh_host(multi=False)
|
|
15
18
|
assert isinstance(tmp, str)
|
|
16
|
-
ssh =
|
|
19
|
+
ssh = SSH(tmp)
|
|
17
20
|
default = f"{ssh.hostname}:{ssh.run('echo $HOME').op}/data/share_nfs"
|
|
18
|
-
share_info = display_options("Choose a share path: ", options=
|
|
21
|
+
share_info = display_options("Choose a share path: ", options=L(ssh.run("cat /etc/exports").op.split("\n")).filter(lambda x: not x.startswith("#")).apply(lambda x: f"{ssh.hostname}:{x.split(' ')[0]}").list + [default], default=default)
|
|
19
22
|
assert isinstance(share_info, str), f"share_info must be a string. Got {type(share_info)}"
|
|
20
23
|
remote_server = share_info.split(":")[0]
|
|
21
24
|
share_path = share_info.split(":")[1]
|
|
22
25
|
|
|
23
26
|
if platform.system() == "Linux":
|
|
24
|
-
mount_path_1 =
|
|
27
|
+
mount_path_1 = P(share_path)
|
|
25
28
|
print(remote_server)
|
|
26
|
-
mount_path_2 =
|
|
27
|
-
if str(mount_path_1).startswith("/home"): mount_path_3 =
|
|
29
|
+
mount_path_2 = P.home().joinpath(f"data/mount_nfs/{remote_server}")
|
|
30
|
+
if str(mount_path_1).startswith("/home"): mount_path_3 = P.home().joinpath(*mount_path_1.parts[3:])
|
|
28
31
|
else: mount_path_3 = mount_path_2
|
|
29
32
|
local_mount_point = display_options(msg="choose mount path OR input custom one", options=[mount_path_1, mount_path_2, mount_path_3], default=mount_path_2, custom_input=True)
|
|
30
|
-
assert isinstance(local_mount_point,
|
|
31
|
-
local_mount_point =
|
|
33
|
+
assert isinstance(local_mount_point, P), f"local_mount_point must be a pathlib.Path. Got {type(local_mount_point)}"
|
|
34
|
+
local_mount_point = P(local_mount_point).expanduser()
|
|
32
35
|
PROGRAM_PATH.write_text(f"""
|
|
33
36
|
share_info={share_info}
|
|
34
37
|
remote_server={remote_server}
|
|
@@ -36,14 +39,14 @@ share_path={share_path}
|
|
|
36
39
|
local_mount_point={local_mount_point}
|
|
37
40
|
""")
|
|
38
41
|
elif platform.system() == "Windows":
|
|
39
|
-
print(
|
|
42
|
+
print(Terminal().run("Get-PSDrive -PSProvider 'FileSystem'", shell="powershell").op)
|
|
40
43
|
driver_letter = input(r"Choose driver letter (e.g. Z:\) (avoid the ones already used) : ") or "Z:\\"
|
|
41
44
|
PROGRAM_PATH.write_text(f"""
|
|
42
45
|
$server = "{remote_server}"
|
|
43
46
|
$sharePath = "{share_path}"
|
|
44
47
|
$driveLetter = "{driver_letter}"
|
|
45
48
|
""")
|
|
46
|
-
#
|
|
49
|
+
# P.home().joinpath(f"data/mount_nfs/{remote_server}").symlink_to(target="") # can't be created until the mount is finished
|
|
47
50
|
print(PROGRAM_PATH.read_text())
|
|
48
51
|
|
|
49
52
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
from machineconfig.utils.utils import PROGRAM_PATH
|
|
4
|
+
from crocodile.file_management import P
|
|
4
5
|
import platform
|
|
5
6
|
|
|
6
7
|
|
|
@@ -9,8 +10,8 @@ def main():
|
|
|
9
10
|
drive_location = input("Enter the network drive location (ex: //192.168.1.100/Share): ")
|
|
10
11
|
machine_name = drive_location.split("//")[1].split("/")[0]
|
|
11
12
|
mount_point = input(f"Enter the mount point directory (ex: /mnt/network) [default: ~/data/mount_nw/{machine_name}]: ")
|
|
12
|
-
if mount_point == "": mount_point =
|
|
13
|
-
else: mount_point =
|
|
13
|
+
if mount_point == "": mount_point = P.home().joinpath(fr"data/mount_nw/{machine_name}")
|
|
14
|
+
else: mount_point = P(mount_point).expanduser()
|
|
14
15
|
|
|
15
16
|
username = input(f"Enter the username: ")
|
|
16
17
|
password = input(f"Enter the password: ")
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
"""Mount a remote SSHFS share on a local directory
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
from platform import system
|
|
7
|
+
from crocodile.meta import SSH, Terminal
|
|
8
|
+
from crocodile.file_management import P
|
|
9
|
+
|
|
7
10
|
from machineconfig.utils.utils import PROGRAM_PATH, choose_ssh_host
|
|
8
11
|
|
|
9
12
|
|
|
@@ -14,15 +17,15 @@ def main():
|
|
|
14
17
|
if share_info == "":
|
|
15
18
|
tmp = choose_ssh_host(multi=False)
|
|
16
19
|
assert isinstance(tmp, str)
|
|
17
|
-
ssh =
|
|
20
|
+
ssh = SSH(host=tmp)
|
|
18
21
|
share_info = f"{ssh.username}@{ssh.hostname}:{ssh.run('echo $HOME').op}/data/share_ssh"
|
|
19
22
|
else:
|
|
20
|
-
ssh =
|
|
21
|
-
print(
|
|
23
|
+
ssh = SSH(share_info.split(":")[0])
|
|
24
|
+
print(Terminal().run("net use", shell="powershell").op)
|
|
22
25
|
driver_letter = input(r"Choose driver letter (e.g. Z:\) (avoid the ones already used) : ") or "Z:\\"
|
|
23
26
|
|
|
24
27
|
mount_point = input(f"Enter the mount point directory (ex: /mnt/network) [default: ~/data/mount_ssh/{ssh.hostname}]: ")
|
|
25
|
-
if mount_point == "": mount_point =
|
|
28
|
+
if mount_point == "": mount_point = P.home().joinpath(fr"data/mount_ssh/{ssh.hostname}")
|
|
26
29
|
|
|
27
30
|
if system() == "Linux":
|
|
28
31
|
txt = fr"""
|
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
"""Repos
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import crocodile.toolbox as tb
|
|
6
|
-
import argparse
|
|
7
|
-
from machineconfig.utils.utils import write_shell_script, CONFIG_PATH, DEFAULTS_PATH
|
|
8
5
|
from rich import print as pprint
|
|
6
|
+
from machineconfig.utils.utils import write_shell_script, CONFIG_PATH, DEFAULTS_PATH
|
|
7
|
+
from crocodile.file_management import P, install_n_import, Read, Save
|
|
8
|
+
from crocodile.core import randstr
|
|
9
|
+
import argparse
|
|
9
10
|
from dataclasses import dataclass
|
|
10
11
|
from enum import Enum
|
|
11
12
|
from typing import Optional, Any
|
|
12
|
-
# tm =
|
|
13
|
+
# tm = Terminal()
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class GitAction(Enum):
|
|
@@ -26,7 +27,7 @@ class RepoRecord:
|
|
|
26
27
|
version: dict[str, str]
|
|
27
28
|
|
|
28
29
|
|
|
29
|
-
def git_action(path:
|
|
30
|
+
def git_action(path: P, action: GitAction, mess: Optional[str] = None, r: bool = False) -> str:
|
|
30
31
|
from git.exc import InvalidGitRepositoryError
|
|
31
32
|
from git.repo import Repo
|
|
32
33
|
try:
|
|
@@ -43,7 +44,7 @@ echo '>>>>>>>>> {action}'
|
|
|
43
44
|
cd '{path}'
|
|
44
45
|
'''
|
|
45
46
|
if action == GitAction.commit:
|
|
46
|
-
if mess is None: mess = "auto_commit_" +
|
|
47
|
+
if mess is None: mess = "auto_commit_" + randstr()
|
|
47
48
|
program += f'''
|
|
48
49
|
git add .; git commit -am "{mess}"
|
|
49
50
|
'''
|
|
@@ -76,19 +77,19 @@ def main():
|
|
|
76
77
|
parser.add_argument("--cloud", "-c", help=f"cloud", default=None)
|
|
77
78
|
args = parser.parse_args()
|
|
78
79
|
|
|
79
|
-
if args.directory == "": repos_root =
|
|
80
|
-
else: repos_root =
|
|
81
|
-
_ =
|
|
80
|
+
if args.directory == "": repos_root = P.home().joinpath("code") # it is a positional argument, can never be empty.
|
|
81
|
+
else: repos_root = P(args.directory).expanduser().absolute()
|
|
82
|
+
_ = install_n_import("git", "gitpython")
|
|
82
83
|
|
|
83
84
|
program = ""
|
|
84
85
|
if args.record:
|
|
85
86
|
res = record_repos(repos_root=str(repos_root))
|
|
86
87
|
pprint(f"Recorded repositories:\n", res)
|
|
87
88
|
save_path = CONFIG_PATH.joinpath("repos").joinpath(repos_root.rel2home()).joinpath("repos.json")
|
|
88
|
-
#
|
|
89
|
-
|
|
90
|
-
pprint(f"Result pickled at {
|
|
91
|
-
if args.cloud is not None:
|
|
89
|
+
# Save.pickle(obj=res, path=save_path)
|
|
90
|
+
Save.json(obj=res, path=save_path)
|
|
91
|
+
pprint(f"Result pickled at {P(save_path)}")
|
|
92
|
+
if args.cloud is not None: P(save_path).to_cloud(rel2home=True, cloud=args.cloud)
|
|
92
93
|
program += f"""\necho '>>>>>>>>> Finished Recording'\n"""
|
|
93
94
|
elif args.clone or args.checkout or args.checkout_to_branch:
|
|
94
95
|
# preferred_remote = input("Enter preferred remote to use (default: None): ") or ""
|
|
@@ -97,7 +98,7 @@ def main():
|
|
|
97
98
|
repos_root = CONFIG_PATH.joinpath("repos").joinpath(repos_root.rel2home()).joinpath("repos.json")
|
|
98
99
|
if not repos_root.exists():
|
|
99
100
|
if args.cloud is None:
|
|
100
|
-
cloud: str =
|
|
101
|
+
cloud: str = Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
|
|
101
102
|
print(f"⚠️ Using default cloud: {cloud}")
|
|
102
103
|
else:
|
|
103
104
|
cloud = args.cloud
|
|
@@ -118,7 +119,7 @@ def main():
|
|
|
118
119
|
|
|
119
120
|
|
|
120
121
|
def record_repos(repos_root: str, r: bool = True) -> list[dict[str, Any]]:
|
|
121
|
-
path_obj =
|
|
122
|
+
path_obj = P(repos_root).expanduser().absolute()
|
|
122
123
|
if path_obj.is_file(): return []
|
|
123
124
|
search_res = path_obj.search("*", files=False)
|
|
124
125
|
res: list[dict[str, Any]] = []
|
|
@@ -130,10 +131,10 @@ def record_repos(repos_root: str, r: bool = True) -> list[dict[str, Any]]:
|
|
|
130
131
|
return res
|
|
131
132
|
|
|
132
133
|
|
|
133
|
-
def record_a_repo(path:
|
|
134
|
+
def record_a_repo(path: P, search_parent_directories: bool = False, preferred_remote: Optional[str] = None):
|
|
134
135
|
from git.repo import Repo
|
|
135
136
|
repo = Repo(path, search_parent_directories=search_parent_directories) # get list of remotes using git python
|
|
136
|
-
repo_root =
|
|
137
|
+
repo_root = P(repo.working_dir).absolute()
|
|
137
138
|
remotes = {remote.name: remote.url for remote in repo.remotes}
|
|
138
139
|
if preferred_remote is not None:
|
|
139
140
|
if preferred_remote in remotes: remotes = {preferred_remote: remotes[preferred_remote]}
|
|
@@ -157,10 +158,10 @@ def record_a_repo(path: tb.P, search_parent_directories: bool = False, preferred
|
|
|
157
158
|
|
|
158
159
|
def install_repos(specs_path: str, clone: bool = True, checkout_to_recorded_commit: bool = False, checkout_to_branch: bool = False, editable_install: bool = False, preferred_remote: Optional[str] = None):
|
|
159
160
|
program = ""
|
|
160
|
-
path_obj =
|
|
161
|
-
repos: list[dict[str, Any]] =
|
|
161
|
+
path_obj = P(specs_path).expanduser().absolute()
|
|
162
|
+
repos: list[dict[str, Any]] = Read.json(path_obj)
|
|
162
163
|
for repo in repos:
|
|
163
|
-
parent_dir =
|
|
164
|
+
parent_dir = P(repo["parent_dir"]).expanduser().absolute().create()
|
|
164
165
|
for idx, (remote_name, remote_url) in enumerate(repo["remotes"].items()):
|
|
165
166
|
if clone:
|
|
166
167
|
if idx == 0: # clone
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
from crocodile.msc.odds import capture_from_webcam
|
|
3
|
-
|
|
3
|
+
from crocodile.meta import Terminal
|
|
4
4
|
import argparse
|
|
5
5
|
|
|
6
6
|
|
|
@@ -11,7 +11,7 @@ def main():
|
|
|
11
11
|
|
|
12
12
|
img_path = capture_from_webcam(show=False, wait=False, save=True)
|
|
13
13
|
if args.to_text:
|
|
14
|
-
q =
|
|
14
|
+
q = Terminal().run(f"cd ~/AppData/Local/Tesseract-OCR; pytesseract '{img_path}'", shell="pwsh").capture().op
|
|
15
15
|
print(q)
|
|
16
16
|
else:
|
|
17
17
|
print(img_path)
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
|
|
2
|
+
"""
|
|
3
|
+
slidev
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from machineconfig.utils.utils import CONFIG_PATH, PROGRAM_PATH, print_code
|
|
7
|
+
from crocodile.meta import Terminal, P
|
|
8
|
+
# from crocodile.environment import get_network_addresses
|
|
9
|
+
import subprocess
|
|
10
|
+
import platform
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
PORT_DEFAULT = 3030
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
SLIDEV_REPO = CONFIG_PATH.joinpath(".cache/slidev")
|
|
17
|
+
if not SLIDEV_REPO.joinpath("components").exists():
|
|
18
|
+
# assert slidev is installed first
|
|
19
|
+
Terminal(stderr=subprocess.PIPE, stdin=subprocess.PIPE, stdout=subprocess.PIPE).run(f"cd {SLIDEV_REPO.parent};npm init slidev")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def jupyter_to_markdown(file: P):
|
|
23
|
+
op_dir = file.parent.joinpath("presentation")
|
|
24
|
+
|
|
25
|
+
# https://nbconvert.readthedocs.io/en/latest/nbconvert_library.html
|
|
26
|
+
# from nbconvert.exporters.markdown import MarkdownExporter
|
|
27
|
+
# import nbformat
|
|
28
|
+
# nb = nbformat.read(file, as_version=4)
|
|
29
|
+
# assert isinstance(nb, nbformat.notebooknode.NotebookNode), f"{file} is not a notebook"
|
|
30
|
+
# e = MarkdownExporter(exclude_input=True, exclude_input_prompt=True, exclude_output_prompt=True)
|
|
31
|
+
# body, resources = e.from_notebook_node(nb=nb)
|
|
32
|
+
# op_dir.joinpath("slides_raw.md").write_text(body)
|
|
33
|
+
# for key, value in resources['outputs'].items():
|
|
34
|
+
|
|
35
|
+
cmd = f"jupyter nbconvert --to markdown --no-prompt --no-input --output-dir {op_dir} --output slides_raw.md {file}"
|
|
36
|
+
Terminal().run(cmd, shell="powershell").print()
|
|
37
|
+
cmd = f"jupyter nbconvert --to html --no-prompt --no-input --output-dir {op_dir} {file}"
|
|
38
|
+
Terminal().run(cmd, shell="powershell").print()
|
|
39
|
+
# cmd = f"jupyter nbconvert --to pdf --no-prompt --no-input --output-dir {op_dir} {file}"
|
|
40
|
+
# Terminal().run(cmd, shell="powershell").print()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
op_file = op_dir.joinpath("slides_raw.md")
|
|
44
|
+
slide_separator = '\n\n---\n\n'
|
|
45
|
+
md = op_file.read_text().replace('\n\n\n\n', slide_separator)
|
|
46
|
+
md = slide_separator.join([item for item in md.split(slide_separator) if bool(item.strip())]) # remove empty slides.
|
|
47
|
+
op_file.with_name("slides.md").write_text(md)
|
|
48
|
+
return op_dir
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def main() -> None:
|
|
52
|
+
import argparse
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
parser = argparse.ArgumentParser()
|
|
56
|
+
parser.add_argument("-d", "--directory", default=None, help="Directory of the report")
|
|
57
|
+
parser.add_argument("-j", "--jupyter-file", default=None, help="Jupyter notebook file to convert to slides. If not provided, slides.md is used.")
|
|
58
|
+
parser.add_argument("--port", default=PORT_DEFAULT, help=f"Port to serve the report, default to {PORT_DEFAULT}")
|
|
59
|
+
args = parser.parse_args()
|
|
60
|
+
|
|
61
|
+
port = args.port
|
|
62
|
+
|
|
63
|
+
if args.jupyter_file is not None:
|
|
64
|
+
report_dir = jupyter_to_markdown(P(args.jupyter_file))
|
|
65
|
+
else:
|
|
66
|
+
if args.directory is None:
|
|
67
|
+
report_dir = P.cwd()
|
|
68
|
+
else:
|
|
69
|
+
report_dir = P(args.directory)
|
|
70
|
+
|
|
71
|
+
assert report_dir.exists(), f"{report_dir} does not exist"
|
|
72
|
+
assert report_dir.is_dir(), f"{report_dir} is not a directory"
|
|
73
|
+
|
|
74
|
+
md_file = report_dir.joinpath("slides.md")
|
|
75
|
+
if not md_file.exists():
|
|
76
|
+
res = report_dir.search("*.md")
|
|
77
|
+
if len(res) == 1:
|
|
78
|
+
md_file = res.list[0]
|
|
79
|
+
else:
|
|
80
|
+
raise FileNotFoundError(f"slides.md not found in {report_dir}")
|
|
81
|
+
|
|
82
|
+
report_dir.search().apply(lambda x: x.copy(folder=SLIDEV_REPO, overwrite=True))
|
|
83
|
+
if md_file.name != "slides.md":
|
|
84
|
+
SLIDEV_REPO.joinpath(md_file.name).with_name(name="slides.md", inplace=True, overwrite=True)
|
|
85
|
+
|
|
86
|
+
# from machineconfig.utils.utils import check_tool_exists
|
|
87
|
+
# check_tool_exists(tool_name="slidev", install_script="npm i -g @slidev/cli")
|
|
88
|
+
|
|
89
|
+
import socket
|
|
90
|
+
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
|
|
91
|
+
except Exception:
|
|
92
|
+
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
|
|
93
|
+
local_ip_v4 = socket.gethostbyname(socket.gethostname())
|
|
94
|
+
|
|
95
|
+
print(f"Presentation is served at http://{platform.node()}:{port}")
|
|
96
|
+
print(f"Presentation is served at http://localhost:{port}")
|
|
97
|
+
print(f"Presentation is served at http://{local_ip_v4}:{port}")
|
|
98
|
+
program: str = f"cd {SLIDEV_REPO}; slidev --port {port} --remote 0.0.0.0; cd {P.cwd()}"
|
|
99
|
+
PROGRAM_PATH.write_text(program)
|
|
100
|
+
print_code(program, lexer="bash")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == '__main__':
|
|
104
|
+
main()
|
|
@@ -5,53 +5,39 @@ https://glitchbone.github.io/vscode-base16-term/#/3024
|
|
|
5
5
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
# import crocodile.environment as env
|
|
8
|
+
|
|
9
|
+
# # import crocodile.environment as env
|
|
10
|
+
from crocodile.file_management import P
|
|
11
|
+
# from crocodile.meta import Terminal
|
|
10
12
|
from machineconfig.utils.utils import LIBRARY_ROOT
|
|
11
|
-
from machineconfig.utils.installer import
|
|
12
|
-
import os
|
|
13
|
+
from machineconfig.utils.installer import Installer
|
|
14
|
+
# import os
|
|
15
|
+
import subprocess
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
nerd_fonts = {
|
|
19
|
+
"repo_url": "https://github.com/ryanoasis/nerd-fonts",
|
|
20
|
+
"doc": "Nerd Fonts is a project that patches developer targeted fonts with a high number of glyphs (icons)",
|
|
21
|
+
"filename_template_windows_amd_64": "CascadiaCode.zip",
|
|
22
|
+
"filename_template_linux_amd_64": "CascadiaCode.zip",
|
|
23
|
+
"strip_v": False,
|
|
24
|
+
"exe_name": "nerd_fonts"
|
|
25
|
+
}
|
|
13
26
|
|
|
14
27
|
|
|
15
28
|
def install_nerd_fonts():
|
|
16
29
|
# Step 1: download the required fonts that has all the glyphs and install them.
|
|
17
|
-
folder =
|
|
18
|
-
if not isinstance(folder, tb.P): raise ValueError(f"Failed to get latest release. Expected a Path object, got {folder}")
|
|
19
|
-
folder = folder.joinpath("CascadiaCode.zip").download().unzip(inplace=True)
|
|
30
|
+
folder, _version_to_be_installed = Installer.from_dict(d=nerd_fonts, name="nerd_fonts").download(version=None)
|
|
20
31
|
folder.search("*Windows*").apply(lambda p: p.delete(sure=True))
|
|
21
32
|
folder.search("*readme*").apply(lambda p: p.delete(sure=True))
|
|
22
33
|
folder.search("*LICENSE*").apply(lambda p: p.delete(sure=True))
|
|
23
|
-
file =
|
|
24
|
-
|
|
34
|
+
file = P.tmpfile(suffix=".ps1").write_text(LIBRARY_ROOT.joinpath("setup_windows/wt_and_pwsh/install_fonts.ps1").read_text().replace(r".\fonts-to-be-installed", str(folder)))
|
|
35
|
+
subprocess.run(rf"powershell.exe -executionpolicy Bypass -nologo -noninteractive -File {file.str}", check=True)
|
|
25
36
|
folder.delete(sure=True)
|
|
26
37
|
|
|
27
38
|
|
|
28
|
-
def change_shell_profile():
|
|
29
|
-
# Customize powershell profile such that it loads oh-my-posh and the terminal icons automatically.
|
|
30
|
-
# Add arrow keys history functionality to the terminal.
|
|
31
|
-
shell = "pwsh"
|
|
32
|
-
profile_path = tb.Terminal().run("$profile", shell=shell).op2path()
|
|
33
|
-
assert isinstance(profile_path, tb.P), f"Could not find profile path for {shell}."
|
|
34
|
-
local_app_data = os.getenv("LOCALAPPDATA")
|
|
35
|
-
if not isinstance(local_app_data, str):
|
|
36
|
-
raise ValueError("Could not find LOCALAPPDATA environment variable.")
|
|
37
|
-
theme_path = tb.P(local_app_data).joinpath(r"Programs\oh-my-posh\themes").collapseuser().as_posix().replace("~", "$env:USERPROFILE") # organization machine with homeshare confuse H: with ~.
|
|
38
|
-
txt = f"""
|
|
39
|
-
oh-my-posh --init --shell pwsh --config {theme_path}/jandedobbeleer.omp.json | Invoke-Expression
|
|
40
|
-
Import-Module -Name Terminal-Icons
|
|
41
|
-
|
|
42
|
-
# Shows navigable menu of all options when hitting Tab
|
|
43
|
-
Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete
|
|
44
|
-
Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward
|
|
45
|
-
Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward
|
|
46
|
-
Set-PSReadlineOption -PredictionViewStyle History
|
|
47
|
-
# see dynamic help with prerelease.
|
|
48
|
-
"""
|
|
49
|
-
profile_path.modify_text(txt_search=txt, txt_alt=txt, replace_line=True, notfound_append=True)
|
|
50
|
-
|
|
51
|
-
|
|
52
39
|
def main():
|
|
53
40
|
install_nerd_fonts()
|
|
54
|
-
change_shell_profile()
|
|
55
41
|
|
|
56
42
|
|
|
57
43
|
if __name__ == '__main__':
|