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.

Files changed (63) hide show
  1. machineconfig/__init__.py +2 -2
  2. machineconfig/jobs/python/check_installations.py +37 -31
  3. machineconfig/jobs/python/create_bootable_media.py +4 -4
  4. machineconfig/jobs/python/create_zellij_template.py +3 -2
  5. machineconfig/jobs/python/python_cargo_build_share.py +14 -9
  6. machineconfig/jobs/python/python_ve_symlink.py +6 -6
  7. machineconfig/jobs/{python_linux_installers/dev → script_installer}/azure_data_studio.py +6 -5
  8. machineconfig/jobs/{python_windows_installers/dev → script_installer}/bypass_paywall.py +5 -4
  9. machineconfig/jobs/script_installer/code.py +34 -0
  10. machineconfig/jobs/{python_linux_installers/dev → script_installer}/docker_desktop.py +2 -2
  11. machineconfig/jobs/script_installer/ngrok.py +29 -0
  12. machineconfig/jobs/script_installer/skim.py +21 -0
  13. machineconfig/jobs/script_installer/wezterm.py +34 -0
  14. machineconfig/profile/create.py +8 -6
  15. machineconfig/profile/shell.py +15 -13
  16. machineconfig/scripts/python/cloud_copy.py +14 -13
  17. machineconfig/scripts/python/cloud_mount.py +27 -11
  18. machineconfig/scripts/python/cloud_repo_sync.py +32 -14
  19. machineconfig/scripts/python/cloud_sync.py +9 -9
  20. machineconfig/scripts/python/croshell.py +3 -3
  21. machineconfig/scripts/python/devops.py +22 -6
  22. machineconfig/scripts/python/devops_add_identity.py +7 -6
  23. machineconfig/scripts/python/devops_add_ssh_key.py +10 -9
  24. machineconfig/scripts/python/devops_backup_retrieve.py +5 -5
  25. machineconfig/scripts/python/devops_devapps_install.py +13 -14
  26. machineconfig/scripts/python/devops_update_repos.py +5 -4
  27. machineconfig/scripts/python/dotfile.py +8 -4
  28. machineconfig/scripts/python/fire_jobs.py +95 -24
  29. machineconfig/scripts/python/ftpx.py +1 -1
  30. machineconfig/scripts/python/mount_nfs.py +13 -10
  31. machineconfig/scripts/python/mount_nw_drive.py +4 -3
  32. machineconfig/scripts/python/mount_ssh.py +8 -5
  33. machineconfig/scripts/python/repos.py +21 -20
  34. machineconfig/scripts/python/snapshot.py +2 -2
  35. machineconfig/scripts/python/start_slidev.py +104 -0
  36. machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +20 -34
  37. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +11 -12
  38. machineconfig/utils/installer.py +96 -204
  39. machineconfig/utils/scheduling.py +1 -1
  40. machineconfig/utils/utils.py +102 -51
  41. machineconfig/utils/ve.py +96 -13
  42. {machineconfig-1.7.dist-info → machineconfig-1.8.dist-info}/METADATA +8 -8
  43. machineconfig-1.8.dist-info/RECORD +70 -0
  44. machineconfig/jobs/python_generic_installers/archive/gopass.py +0 -18
  45. machineconfig/jobs/python_generic_installers/archive/nvim.py +0 -20
  46. machineconfig/jobs/python_generic_installers/archive/opencommit.py +0 -25
  47. machineconfig/jobs/python_generic_installers/archive/strongbox.py +0 -33
  48. machineconfig/jobs/python_generic_installers/dev/__init__.py +0 -0
  49. machineconfig/jobs/python_linux_installers/archive/__init__.py +0 -0
  50. machineconfig/jobs/python_linux_installers/archive/bandwhich.py +0 -14
  51. machineconfig/jobs/python_linux_installers/archive/ranger.py +0 -19
  52. machineconfig/jobs/python_linux_installers/dev/bytehound.py +0 -20
  53. machineconfig/jobs/python_linux_installers/dev/nnn.py +0 -22
  54. machineconfig/jobs/python_windows_installers/archive/ntop.py +0 -21
  55. machineconfig/jobs/python_windows_installers/dev/obs_background_removal_plugin.py +0 -22
  56. machineconfig/scripts/python/choose_ohmybash_theme.py +0 -31
  57. machineconfig/scripts/python/choose_ohmyposh_theme.py +0 -57
  58. machineconfig/utils/pandas_type.py +0 -37
  59. machineconfig/utils/to_exe.py +0 -7
  60. machineconfig-1.7.dist-info/RECORD +0 -81
  61. /machineconfig/jobs/{python_generic_installers/archive → script_installer}/__init__.py +0 -0
  62. {machineconfig-1.7.dist-info → machineconfig-1.8.dist-info}/WHEEL +0 -0
  63. {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
- import crocodile.toolbox as tb
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(tb.P(args.path))
46
- if not path_obj.exists(): path_obj = match_file_name(args.path)
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 = display_options(msg="Choose a file to run", options=files, fzf=True, multi=False)
56
- assert not isinstance(choice_file, list), f"choice_file must be a string. Got {type(choice_file)}"
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'{tb.P(choice_file).parent}')
99
- from {tb.P(choice_file).stem} import *
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='Imported Script')
117
+ print_code(code=r'''{txt}''', lexer='python', desc='Import Script')
109
118
  """ + txt
110
- choice_file = tb.P.tmp().joinpath(f'tmp_scripts/python/{tb.P(choice_file).parent.name}_{tb.P(choice_file).stem}_{tb.randstr()}.py').create(parents_only=True).write_text(txt)
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
- tmp = f"'{kwargs}'" if kwargs else ''
122
- command = f"{exe} -m fire {choice_file} {choice_function} {tmp}"
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 {tb.P.cwd()}"
135
- else: command = rf""" cd /d {choice_file.parent} & {exe} {choice_file.name} """
136
- # command = f"cd {choice_file.parent}; {exe} {choice_file.name}; cd {tb.P.cwd()}"
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
- if "ipdb" in command: tb.install_n_import("ipdb")
139
- if "pudb" in command: tb.install_n_import("pudb")
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: tb.install_n_import("clipboard").copy(command)
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(tb.P(file_path).read_text(encoding='utf-8'))
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 -- {tb.Display.get_repr(module__doc__, limit=150) if module__doc__ is not None else 'NoDocs'}"
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
- # tb.Struct(get_attrs(arg.annotation)).print(as_yaml=True)
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
- import crocodile.toolbox as tb
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 = tb.SSH(tmp)
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=tb.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)
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 = tb.P(share_path)
27
+ mount_path_1 = P(share_path)
25
28
  print(remote_server)
26
- mount_path_2 = tb.P.home().joinpath(f"data/mount_nfs/{remote_server}")
27
- if str(mount_path_1).startswith("/home"): mount_path_3 = tb.P.home().joinpath(*mount_path_1.parts[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, tb.P), f"local_mount_point must be a pathlib.Path. Got {type(local_mount_point)}"
31
- local_mount_point = tb.P(local_mount_point).expanduser()
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(tb.Terminal().run("Get-PSDrive -PSProvider 'FileSystem'", shell="powershell").op)
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
- # tb.P.home().joinpath(f"data/mount_nfs/{remote_server}").symlink_to(target="") # can't be created until the mount is finished
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
- import crocodile.toolbox as tb
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 = tb.P.home().joinpath(fr"data/mount_nw/{machine_name}")
13
- else: mount_point = tb.P(mount_point).expanduser()
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
- import crocodile.toolbox as tb
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 = tb.SSH(host=tmp)
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 = tb.SSH(share_info.split(":")[0])
21
- print(tb.Terminal().run("net use", shell="powershell").op)
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 = tb.P.home().joinpath(fr"data/mount_ssh/{ssh.hostname}")
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 = tb.Terminal()
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: tb.P, action: GitAction, mess: Optional[str] = None, r: bool = False) -> str:
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_" + tb.randstr()
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 = tb.P.home().joinpath("code") # it is a positional argument, can never be empty.
80
- else: repos_root = tb.P(args.directory).expanduser().absolute()
81
- _ = tb.install_n_import("git", "gitpython")
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
- # tb.Save.pickle(obj=res, path=save_path)
89
- tb.Save.json(obj=res, path=save_path)
90
- pprint(f"Result pickled at {tb.P(save_path)}")
91
- if args.cloud is not None: tb.P(save_path).to_cloud(rel2home=True, cloud=args.cloud)
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 = tb.Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
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 = tb.P(repos_root).expanduser().absolute()
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: tb.P, search_parent_directories: bool = False, preferred_remote: Optional[str] = None):
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 = tb.P(repo.working_dir).absolute()
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 = tb.P(specs_path).expanduser().absolute()
161
- repos: list[dict[str, Any]] = tb.Read.json(path_obj)
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 = tb.P(repo["parent_dir"]).expanduser().absolute().create()
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
- import crocodile.toolbox as tb
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 = tb.Terminal().run(f"cd ~/AppData/Local/Tesseract-OCR; pytesseract '{img_path}'", shell="pwsh").capture().op
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
- import crocodile.toolbox as tb
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 get_latest_release
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 = get_latest_release(repo_url="https://github.com/ryanoasis/nerd-fonts", exe_name="NOTHING",)
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 = tb.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)))
24
- tb.subprocess.run(rf"powershell.exe -executionpolicy Bypass -nologo -noninteractive -File {file.str}", check=True)
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__':