machineconfig 1.94__py3-none-any.whl → 1.95__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 (120) hide show
  1. machineconfig/cluster/data_transfer.py +2 -1
  2. machineconfig/cluster/job_params.py +1 -1
  3. machineconfig/cluster/script_execution.py +1 -1
  4. machineconfig/jobs/__pycache__/__init__.cpython-311.pyc +0 -0
  5. machineconfig/jobs/linux/msc/lid.sh +2 -4
  6. machineconfig/jobs/linux/msc/network.sh +3 -6
  7. machineconfig/jobs/python/check_installations.py +6 -6
  8. machineconfig/jobs/python/checkout_version.py +4 -4
  9. machineconfig/jobs/python/python_cargo_build_share.py +2 -2
  10. machineconfig/jobs/python/python_ve_symlink.py +4 -4
  11. machineconfig/jobs/python/vscode/api.py +2 -2
  12. machineconfig/jobs/python/vscode/link_ve.py +4 -4
  13. machineconfig/jobs/python/vscode/select_interpreter.py +4 -4
  14. machineconfig/jobs/python/vscode/sync_code.py +6 -6
  15. machineconfig/jobs/python_custom_installers/archive/ngrok.py +4 -4
  16. machineconfig/jobs/python_custom_installers/dev/aider.py +4 -4
  17. machineconfig/jobs/python_custom_installers/dev/alacritty.py +4 -4
  18. machineconfig/jobs/python_custom_installers/dev/brave.py +4 -4
  19. machineconfig/jobs/python_custom_installers/dev/bypass_paywall.py +4 -4
  20. machineconfig/jobs/python_custom_installers/dev/code.py +4 -4
  21. machineconfig/jobs/python_custom_installers/dev/docker.py +4 -4
  22. machineconfig/jobs/python_custom_installers/dev/docker_desktop.py +4 -4
  23. machineconfig/jobs/python_custom_installers/dev/espanso.py +8 -8
  24. machineconfig/jobs/python_custom_installers/dev/goes.py +4 -4
  25. machineconfig/jobs/python_custom_installers/dev/lvim.py +4 -4
  26. machineconfig/jobs/python_custom_installers/dev/nerdfont.py +4 -4
  27. machineconfig/jobs/python_custom_installers/dev/redis.py +4 -4
  28. machineconfig/jobs/python_custom_installers/dev/warp-cli.py +4 -4
  29. machineconfig/jobs/python_custom_installers/dev/wezterm.py +4 -4
  30. machineconfig/jobs/python_custom_installers/gh.py +6 -6
  31. machineconfig/jobs/python_custom_installers/hx.py +28 -58
  32. machineconfig/jobs/python_custom_installers/scripts/linux/brave.sh +4 -8
  33. machineconfig/jobs/python_custom_installers/scripts/linux/docker.sh +5 -10
  34. machineconfig/jobs/python_custom_installers/scripts/linux/docker_start.sh +3 -6
  35. machineconfig/jobs/python_custom_installers/scripts/linux/edge.sh +3 -6
  36. machineconfig/jobs/python_custom_installers/scripts/linux/nerdfont.sh +5 -10
  37. machineconfig/jobs/python_custom_installers/scripts/linux/pgsql.sh +4 -8
  38. machineconfig/jobs/python_custom_installers/scripts/linux/redis.sh +5 -10
  39. machineconfig/jobs/python_custom_installers/scripts/linux/timescaledb.sh +6 -12
  40. machineconfig/jobs/python_custom_installers/scripts/linux/vscode.sh +9 -8
  41. machineconfig/jobs/python_custom_installers/scripts/linux/warp-cli.sh +5 -10
  42. machineconfig/jobs/python_custom_installers/scripts/linux/wezterm.sh +3 -6
  43. machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-311.pyc +0 -0
  44. machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-311.pyc +0 -0
  45. machineconfig/profile/shell.py +26 -47
  46. machineconfig/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  47. machineconfig/scripts/cloud/init.sh +9 -18
  48. machineconfig/scripts/linux/fire +5 -24
  49. machineconfig/scripts/linux/share_cloud.sh +6 -12
  50. machineconfig/scripts/python/__pycache__/__init__.cpython-311.pyc +0 -0
  51. machineconfig/scripts/python/__pycache__/cloud_copy.cpython-311.pyc +0 -0
  52. machineconfig/scripts/python/__pycache__/cloud_mount.cpython-311.pyc +0 -0
  53. machineconfig/scripts/python/__pycache__/cloud_repo_sync.cpython-311.pyc +0 -0
  54. machineconfig/scripts/python/__pycache__/cloud_sync.cpython-311.pyc +0 -0
  55. machineconfig/scripts/python/__pycache__/croshell.cpython-311.pyc +0 -0
  56. machineconfig/scripts/python/__pycache__/devops.cpython-311.pyc +0 -0
  57. machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-311.pyc +0 -0
  58. machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-311.pyc +0 -0
  59. machineconfig/scripts/python/__pycache__/fire_jobs.cpython-311.pyc +0 -0
  60. machineconfig/scripts/python/__pycache__/get_zellij_cmd.cpython-311.pyc +0 -0
  61. machineconfig/scripts/python/__pycache__/repos.cpython-311.pyc +0 -0
  62. machineconfig/scripts/python/archive/im2text.py +30 -30
  63. machineconfig/scripts/python/archive/tmate_conn.py +10 -13
  64. machineconfig/scripts/python/archive/tmate_start.py +12 -16
  65. machineconfig/scripts/python/choose_wezterm_theme.py +9 -18
  66. machineconfig/scripts/python/cloud_copy.py +38 -93
  67. machineconfig/scripts/python/cloud_manager.py +61 -53
  68. machineconfig/scripts/python/cloud_mount.py +23 -34
  69. machineconfig/scripts/python/cloud_repo_sync.py +20 -69
  70. machineconfig/scripts/python/cloud_sync.py +35 -45
  71. machineconfig/scripts/python/croshell.py +48 -73
  72. machineconfig/scripts/python/devops.py +50 -104
  73. machineconfig/scripts/python/devops_add_identity.py +41 -101
  74. machineconfig/scripts/python/devops_add_ssh_key.py +33 -140
  75. machineconfig/scripts/python/devops_backup_retrieve.py +23 -112
  76. machineconfig/scripts/python/devops_devapps_install.py +0 -4
  77. machineconfig/scripts/python/devops_update_repos.py +1 -1
  78. machineconfig/scripts/python/fire_jobs.py +73 -25
  79. machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-311.pyc +0 -0
  80. machineconfig/scripts/python/helpers/__pycache__/cloud_helpers.cpython-311.pyc +0 -0
  81. machineconfig/scripts/python/helpers/__pycache__/helpers2.cpython-311.pyc +0 -0
  82. machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-311.pyc +0 -0
  83. machineconfig/scripts/python/helpers/__pycache__/repo_sync_helpers.cpython-311.pyc +0 -0
  84. machineconfig/scripts/python/helpers/cloud_helpers.py +37 -34
  85. machineconfig/scripts/python/helpers/helpers2.py +17 -31
  86. machineconfig/scripts/python/helpers/repo_sync_helpers.py +19 -54
  87. machineconfig/scripts/python/pomodoro.py +1 -1
  88. machineconfig/scripts/python/repos.py +49 -34
  89. machineconfig/scripts/python/wifi_conn.py +5 -3
  90. machineconfig/scripts/windows/fire.ps1 +27 -15
  91. machineconfig/settings/__pycache__/__init__.cpython-311.pyc +0 -0
  92. machineconfig/settings/shells/ipy/profiles/default/__pycache__/__init__.cpython-311.pyc +0 -0
  93. machineconfig/settings/shells/ipy/profiles/default/startup/__pycache__/__init__.cpython-311.pyc +0 -0
  94. machineconfig/settings/shells/ipy/profiles/default/startup/__pycache__/playext.cpython-311.pyc +0 -0
  95. machineconfig/setup_linux/nix/cli_installation.sh +9 -18
  96. machineconfig/setup_linux/others/openssh-server_add_pub_key.sh +3 -6
  97. machineconfig/setup_linux/web_shortcuts/all.sh +5 -10
  98. machineconfig/setup_linux/web_shortcuts/ascii_art.sh +7 -14
  99. machineconfig/setup_linux/web_shortcuts/croshell.sh +6 -12
  100. machineconfig/setup_linux/web_shortcuts/interactive.sh +34 -68
  101. machineconfig/setup_linux/web_shortcuts/ssh.sh +8 -16
  102. machineconfig/setup_linux/web_shortcuts/update_system.sh +7 -14
  103. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +16 -12
  104. machineconfig/utils/ai/browser_user_wrapper.py +60 -45
  105. machineconfig/utils/ai/generate_file_checklist.py +4 -7
  106. machineconfig/utils/ai/url2md.py +13 -5
  107. machineconfig/utils/{utils_code.py → code.py} +4 -10
  108. machineconfig/utils/installer.py +4 -10
  109. machineconfig/utils/{utils_links.py → links.py} +9 -20
  110. machineconfig/utils/{utils_options.py → options.py} +10 -20
  111. machineconfig/utils/{utils_path.py → path.py} +28 -80
  112. machineconfig/utils/procs.py +26 -30
  113. machineconfig/utils/scheduling.py +11 -11
  114. machineconfig/utils/utils.py +12 -19
  115. machineconfig/utils/ve.py +5 -21
  116. machineconfig/utils/ve_utils/ve2.py +15 -2
  117. {machineconfig-1.94.dist-info → machineconfig-1.95.dist-info}/METADATA +4 -2
  118. {machineconfig-1.94.dist-info → machineconfig-1.95.dist-info}/RECORD +120 -118
  119. {machineconfig-1.94.dist-info → machineconfig-1.95.dist-info}/WHEEL +1 -1
  120. {machineconfig-1.94.dist-info → machineconfig-1.95.dist-info}/top_level.txt +0 -0
@@ -7,170 +7,81 @@ from machineconfig.utils.utils import LIBRARY_ROOT, DEFAULTS_PATH, print_code, c
7
7
  from machineconfig.scripts.python.helpers.helpers2 import ES
8
8
  from platform import system
9
9
  from typing import Any, Literal, Optional
10
+ from rich.console import Console
11
+ from rich.panel import Panel
10
12
 
11
13
 
12
14
  OPTIONS = Literal["BACKUP", "RETRIEVE"]
13
15
 
14
16
 
15
17
  def main_backup_retrieve(direction: OPTIONS, which: Optional[str] = None):
18
+ console = Console()
19
+
16
20
  try:
17
21
  cloud: str = Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
18
- print(f"""
19
- ╔{'═' * 70}╗
20
- ║ ⚠️ DEFAULT CLOUD CONFIGURATION ║
21
- ╠{'═' * 70}╣
22
- ║ 🌥️ Using default cloud: {cloud:<52} ║
23
- ╚{'═' * 70}╝
24
- """)
22
+ console.print(Panel(f"⚠️ DEFAULT CLOUD CONFIGURATION\n🌥️ Using default cloud: {cloud}", title="[bold blue]Cloud Configuration[/bold blue]", border_style="blue"))
25
23
  except (FileNotFoundError, KeyError, IndexError):
26
- print(f"""
27
- ╔{'═' * 70}╗
28
- ║ 🔍 DEFAULT CLOUD NOT FOUND ║
29
- ║ 🔄 Please select a cloud configuration from the options below ║
30
- ╚{'═' * 70}╝
31
- """)
24
+ console.print(Panel("🔍 DEFAULT CLOUD NOT FOUND\n🔄 Please select a cloud configuration from the options below", title="[bold red]Error: Cloud Not Found[/bold red]", border_style="red"))
32
25
  cloud = choose_cloud_interactively()
33
26
 
34
27
  bu_file: dict[str, Any] = Read.toml(LIBRARY_ROOT.joinpath("profile/backup.toml"))
35
28
 
36
- print(f"""
37
- ╔{'═' * 70}╗
38
- ║ 🧰 LOADING BACKUP CONFIGURATION ║
39
- ║ 📄 File: {LIBRARY_ROOT.joinpath("profile/backup.toml")} ║
40
- ╚{'═' * 70}╝
41
- """)
29
+ console.print(Panel(f"🧰 LOADING BACKUP CONFIGURATION\n📄 File: {LIBRARY_ROOT.joinpath('profile/backup.toml')}", title="[bold blue]Backup Configuration[/bold blue]", border_style="blue"))
42
30
 
43
31
  if system() == "Linux":
44
32
  bu_file = {key: val for key, val in bu_file.items() if "windows" not in key}
45
- print(f"""
46
- ╔{'═' * 70}╗
47
- ║ 🐧 LINUX ENVIRONMENT DETECTED ║
48
- ║ 🔍 Filtering out Windows-specific entries ║
49
- ║ ✅ Found {len(bu_file)} applicable backup configuration entries ╚{'═' * 70}╝
50
- """)
33
+ console.print(Panel(f"🐧 LINUX ENVIRONMENT DETECTED\n🔍 Filtering out Windows-specific entries\n✅ Found {len(bu_file)} applicable backup configuration entries", title="[bold blue]Linux Environment[/bold blue]", border_style="blue"))
51
34
  elif system() == "Windows":
52
35
  bu_file = {key: val for key, val in bu_file.items() if "linux" not in key}
53
- print(f"""
54
- ╔{'═' * 70}╗
55
- ║ 🪟 WINDOWS ENVIRONMENT DETECTED ║
56
- ║ 🔍 Filtering out Linux-specific entries ║
57
- ║ ✅ Found {len(bu_file)} applicable backup configuration entries ╚{'═' * 70}╝
58
- """)
36
+ console.print(Panel(f"🪟 WINDOWS ENVIRONMENT DETECTED\n🔍 Filtering out Linux-specific entries\n✅ Found {len(bu_file)} applicable backup configuration entries", title="[bold blue]Windows Environment[/bold blue]", border_style="blue"))
59
37
 
60
38
  if which is None:
61
- print(f"""
62
- ╔{'═' * 70}╗
63
- ║ 🔍 SELECT {direction} ITEMS ║
64
- ║ 📋 Choose which configuration entries to process ║
65
- ╚{'═' * 70}╝
66
- """)
39
+ console.print(Panel(f"🔍 SELECT {direction} ITEMS\n📋 Choose which configuration entries to process", title="[bold blue]Select Items[/bold blue]", border_style="blue"))
67
40
  choices = choose_multiple_options(msg=f"WHICH FILE of the following do you want to {direction}?", options=['all'] + list(bu_file.keys()))
68
41
  else:
69
42
  choices = which.split(",") if isinstance(which, str) else which
70
- print(f"""
71
- ╔{'═' * 70}╗
72
- ║ 🔖 PRE-SELECTED ITEMS ║
73
- ║ 📝 Using: {', '.join(choices):<54} ║
74
- ╚{'═' * 70}╝
75
- """)
43
+ console.print(Panel(f"🔖 PRE-SELECTED ITEMS\n📝 Using: {', '.join(choices)}", title="[bold blue]Pre-selected Items[/bold blue]", border_style="blue"))
76
44
 
77
45
  if "all" in choices:
78
46
  items = bu_file
79
- print(f"""
80
- ╔{'═' * 70}╗
81
- ║ 📋 PROCESSING ALL ENTRIES ║
82
- ║ 🔢 Total entries to process: {len(bu_file):<39} ║
83
- ╚{'═' * 70}╝
84
- """)
47
+ console.print(Panel(f"📋 PROCESSING ALL ENTRIES\n🔢 Total entries to process: {len(bu_file)}", title="[bold blue]Process All Entries[/bold blue]", border_style="blue"))
85
48
  else:
86
49
  items = {key: val for key, val in bu_file.items() if key in choices}
87
- print(f"""
88
- ╔{'═' * 70}╗
89
- ║ 📋 PROCESSING SELECTED ENTRIES ║
90
- ║ 🔢 Total entries to process: {len(items):<39} ║
91
- ╚{'═' * 70}╝
92
- """)
93
-
50
+ console.print(Panel(f"📋 PROCESSING SELECTED ENTRIES\n🔢 Total entries to process: {len(items)}", title="[bold blue]Process Selected Entries[/bold blue]", border_style="blue"))
94
51
  program = f"""$cloud = "{cloud}:{ES}" \n """ if system() == "Windows" else f"""cloud="{cloud}:{ES}" \n """
95
-
96
- print(f"""
97
- ╔{'═' * 70}╗
98
- ║ 🚀 GENERATING {direction} SCRIPT ║
99
- ╠{'═' * 70}╣
100
- ║ 🌥️ Cloud: {cloud:<58} ║
101
- ║ 🗂️ Items: {len(items):<58} ║
102
- ╚{'═' * 70}╝
103
- """)
104
-
52
+ console.print(Panel(f"🚀 GENERATING {direction} SCRIPT\n🌥️ Cloud: {cloud}\n🗂️ Items: {len(items)}", title="[bold blue]Script Generation[/bold blue]", border_style="blue"))
105
53
  for item_name, item in items.items():
106
54
  flags = ''
107
55
  flags += 'z' if item['zip'] == 'True' else ''
108
56
  flags += 'e' if item['encrypt'] == 'True' else ''
109
57
  flags += 'r' if item['rel2home'] == 'True' else ''
110
58
  flags += 'o' if system().lower() in item_name else ''
111
-
112
- print(f"""
113
- ╔{'─' * 70}╗
114
- ║ 📦 PROCESSING: {item_name:<53} ║
115
- ╠{'─' * 70}╣
116
- ║ 📂 Path: {P(item['path']).as_posix():<55} ║
117
- ║ 🏳️ Flags: {flags or 'None':<56} ║
118
- ╚{'─' * 70}╝
119
- """)
120
-
59
+ console.print(Panel(f"📦 PROCESSING: {item_name}\n📂 Path: {P(item['path']).as_posix()}\n🏳️ Flags: {flags or 'None'}", title=f"[bold blue]Processing Item: {item_name}[/bold blue]", border_style="blue"))
121
60
  if flags: flags = "-" + flags
122
61
  if direction == "BACKUP":
123
62
  program += f"""\ncloud_copy "{P(item['path']).as_posix()}" $cloud {flags}\n"""
124
63
  elif direction == "RETRIEVE":
125
64
  program += f"""\ncloud_copy $cloud "{P(item['path']).as_posix()}" {flags}\n"""
126
65
  else:
127
- print(f"""
128
- ╔{'═' * 70}
129
- ║ ❌ ERROR: INVALID DIRECTION ║
130
- ║ ⚠️ Direction must be either "BACKUP" or "RETRIEVE" ║
131
- ╚{'═' * 70}╝
132
- """)
133
- raise RuntimeError(f"Unknown direction: {direction}")
134
-
66
+ console.print(Panel("❌ ERROR: INVALID DIRECTION\n⚠️ Direction must be either \"BACKUP\" or \"RETRIEVE\"", title="[bold red]Error: Invalid Direction[/bold red]", border_style="red"))
67
+ raise RuntimeError(f"Unknown direction: {direction}")
135
68
  if item_name == "dotfiles" and system() == "Linux":
136
69
  program += """\nchmod 700 ~/.ssh/*\n"""
137
- print(f"""
138
- ╔{'─' * 70}╗
139
- ║ 🔒 SPECIAL HANDLING: SSH PERMISSIONS ║
140
- ║ 🛠️ Setting secure permissions for SSH files ║
141
- ║ 📝 Command: chmod 700 ~/.ssh/* ║
142
- ╚{'─' * 70}╝
143
- """)
144
-
70
+ console.print(Panel("🔒 SPECIAL HANDLING: SSH PERMISSIONS\n🛠️ Setting secure permissions for SSH files\n📝 Command: chmod 700 ~/.ssh/*", title="[bold blue]Special Handling: SSH Permissions[/bold blue]", border_style="blue"))
145
71
  print_code(program, lexer="shell", desc=f"{direction} script")
146
-
147
- print(f"""
148
- ╔{'═' * 70}╗
149
- ║ ✅ {direction} SCRIPT GENERATION COMPLETE ║
150
- ║ 🚀 Ready to execute the operations ║
151
- ╚{'═' * 70}╝
152
- """)
153
-
72
+ console.print(Panel(f"✅ {direction} SCRIPT GENERATION COMPLETE\n🚀 Ready to execute the operations", title="[bold green]Script Generation Complete[/bold green]", border_style="green"))
154
73
  return program
155
74
 
156
75
 
157
76
  def main(direction: OPTIONS, which: Optional[str] = None):
158
- print(f"""
159
- ╔{'═' * 70}╗
160
- 🔄 {direction} OPERATION STARTED
161
- ║ ⏱️ {'-' * 58} ║
162
- ╚{'═' * 70}╝
163
- """)
77
+ console = Console()
78
+
79
+ console.print(Panel(f"🔄 {direction} OPERATION STARTED\n⏱️ {'-' * 58}", title="[bold blue]Operation Initiated[/bold blue]", border_style="blue"))
164
80
 
165
81
  code = main_backup_retrieve(direction=direction, which=which)
166
82
  from machineconfig.utils.utils import write_shell_script_to_default_program_path
167
83
 
168
- print(f"""
169
- ╔{'═' * 70}╗
170
- ║ 💾 GENERATING SHELL SCRIPT ║
171
- ║ 📄 Filename: backup_retrieve.sh ║
172
- ╚{'═' * 70}╝
173
- """)
84
+ console.print(Panel("💾 GENERATING SHELL SCRIPT\n📄 Filename: backup_retrieve.sh", title="[bold blue]Shell Script Generation[/bold blue]", border_style="blue"))
174
85
 
175
86
  write_shell_script_to_default_program_path(program=code, desc="backup_retrieve.sh")
176
87
 
@@ -155,10 +155,6 @@ def parse_apps_installer_windows(txt: str) -> dict[str, Any]:
155
155
  {a_chunk}
156
156
  {'-' * 50}""")
157
157
  raise e
158
- # Struct(res).print(as_config=True)
159
- # L(chunks).print(sep="-----------------------------------------------------------------------\n\n")
160
- # import time
161
- # time.sleep(10)
162
158
  return res
163
159
 
164
160
 
@@ -75,7 +75,7 @@ cd "{a_repo.working_dir}"
75
75
  program = "\n".join([f"""
76
76
  echo "🔄 {("Updating " + str(a_repo.working_dir)).center(80, "═")}"
77
77
  cd "{a_repo.working_dir}"
78
- {sep.join([f'git pull {remote.name} {a_repo.active_branch.name} &' for remote in a_repo.remotes])}
78
+ {sep.join([f'git pull {remote.name} {a_repo.active_branch.name}' for remote in a_repo.remotes])}
79
79
  """ for a_repo in repos_objs])
80
80
  else: raise NotImplementedError(f"""
81
81
  ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -12,15 +12,15 @@ from machineconfig.scripts.python.helpers.helpers4 import search_for_files_of_in
12
12
  from machineconfig.scripts.python.helpers.helpers4 import convert_kwargs_to_fire_kwargs_str
13
13
  from machineconfig.scripts.python.helpers.helpers4 import parse_pyfile
14
14
  from machineconfig.scripts.python.helpers.helpers4 import get_import_module_code
15
+ from machineconfig.utils.ve_utils.ve1 import get_repo_root
15
16
  from machineconfig.utils.utils import display_options, choose_one_option, PROGRAM_PATH, match_file_name, sanitize_path
16
17
  from machineconfig.utils.ve_utils.ve1 import get_ve_activate_line, get_ve_name_and_ipython_profile
17
- from crocodile.file_management import P, Read
18
+ from crocodile.file_management import P, Read, Save
18
19
  from crocodile.core import randstr
19
20
  import platform
20
21
  from typing import Optional
21
22
  import argparse
22
-
23
- from machineconfig.utils.ve_utils.ve1 import get_repo_root
23
+ import os
24
24
 
25
25
 
26
26
  str2obj = {"True": True, "False": False, "None": None}
@@ -36,19 +36,28 @@ def main() -> None:
36
36
  parser.add_argument("--interactive", "-i", action="store_true", help="Whether to run the job interactively using IPython")
37
37
  parser.add_argument("--debug", "-d", action="store_true", help="debug")
38
38
  parser.add_argument("--choose_function", "-c", action="store_true", help="debug")
39
- parser.add_argument("--loop", "-l", action="store_true", help="infinite recusion (runs again after completion)")
39
+ parser.add_argument("--loop", "-l", action="store_true", help="infinite recusion (runs again after completion/interruption)")
40
40
  parser.add_argument("--jupyter", "-j", action="store_true", help="open in a jupyter notebook")
41
41
  parser.add_argument("--submit_to_cloud", "-C", action="store_true", help="submit to cloud compute")
42
42
  parser.add_argument("--remote", "-r", action="store_true", help="launch on a remote machine")
43
43
  parser.add_argument("--module", "-m", action="store_true", help="launch the main file")
44
44
  parser.add_argument("--streamlit", "-S", action="store_true", help="run as streamlit app")
45
+ parser.add_argument("--environment", "-E", type=str, help="Choose ip, localhost, hostname or arbitrary url", default="")
45
46
  parser.add_argument("--holdDirectory", "-D", action="store_true", help="hold current directory and avoid cd'ing to the script directory")
47
+ parser.add_argument("--PathExport", "-P", action="store_true", help="augment the PYTHONPATH with repo root.")
46
48
  parser.add_argument("--git_pull", "-g", action="store_true", help="Start by pulling the git repo")
47
- parser.add_argument("--optimized", "-O", action="store_true", help="Run the optimized version of the function")
49
+ parser.add_argument("--optimized", "-O", action="store_true", help="Run the optimized version of the function")
48
50
  parser.add_argument("--Nprocess", "-p", type=int, help="Number of processes to use", default=1)
49
- parser.add_argument("--kw", nargs="*", default=None, help="keyword arguments to pass to the function in the form of k1 v1 k2 v2 ... (meaning k1=v1, k2=v2, etc)")
50
51
  parser.add_argument("--zellij_tab", "-z", type=str, dest="zellij_tab", help="open in a new zellij tab")
51
- args = parser.parse_args()
52
+ parser.add_argument("--watch", "-w", action="store_true", help="watch the file for changes")
53
+ parser.add_argument("--kw", nargs="*", default=None, help="keyword arguments to pass to the function in the form of k1 v1 k2 v2 ... (meaning k1=v1, k2=v2, etc)")
54
+
55
+ try:
56
+ args = parser.parse_args()
57
+ except Exception as ex:
58
+ print(f"❌ Failed to parse arguments: {ex}")
59
+ parser.print_help()
60
+ raise ex
52
61
 
53
62
  path_obj = sanitize_path(P(args.path))
54
63
  if not path_obj.exists():
@@ -62,7 +71,8 @@ def main() -> None:
62
71
  choice_file = P(choice_file)
63
72
  else:
64
73
  choice_file = path_obj
65
- print(f"💾 Selected file: {choice_file}")
74
+ repo_root = get_repo_root(str(choice_file))
75
+ print(f"💾 Selected file: {choice_file}. Repo root: {repo_root}")
66
76
 
67
77
  ve_name_suggested, ipy_profile = get_ve_name_and_ipython_profile(choice_file)
68
78
  if ipy_profile is None: ipy_profile = "default"
@@ -118,20 +128,39 @@ def main() -> None:
118
128
  port = 8501
119
129
  toml_path: Optional[P] = None
120
130
  toml_path_maybe = choice_file.parent.joinpath(".streamlit/config.toml")
121
- if toml_path_maybe.exists(): toml_path = toml_path_maybe
131
+ if toml_path_maybe.exists():
132
+ toml_path = toml_path_maybe
122
133
  elif choice_file.parent.name == "pages":
123
134
  toml_path_maybe = choice_file.parent.parent.joinpath(".streamlit/config.toml")
124
135
  if toml_path_maybe.exists(): toml_path = toml_path_maybe
125
136
  if toml_path is not None:
137
+ print(f"📄 Reading config.toml @ {toml_path}")
126
138
  config = Read.toml(toml_path)
127
139
  if "server" in config:
128
140
  if "port" in config["server"]:
129
141
  port = config["server"]["port"]
142
+ secrets_path = toml_path.with_name("secrets.toml")
143
+ if repo_root is not None:
144
+ secrets_template_path = P.home().joinpath(f"dotfiles/creds/streamlit/{P(repo_root).name}/{choice_file.name}/secrets.toml")
145
+ if args.environment != "" and not secrets_path.exists() and secrets_template_path.exists():
146
+ secrets_template = Read.toml(secrets_template_path)
147
+ if args.environment == "ip": host_url = f"http://{local_ip_v4}:{port}/oauth2callback"
148
+ elif args.environment == "localhost": host_url = f"http://localhost:{port}/oauth2callback"
149
+ elif args.environment == "hostname": host_url = f"http://{computer_name}:{port}/oauth2callback"
150
+ else: host_url = f"http://{args.environment}:{port}/oauth2callback"
151
+ try:
152
+ secrets_template["auth"]["redirect_uri"] = host_url
153
+ secrets_template["auth"]["cookie_secret"] = randstr(35)
154
+ secrets_template["auth"]["auth0"]["redirect_uri"] = host_url
155
+ Save.toml(obj=secrets_template, path=secrets_path)
156
+ except Exception as ex:
157
+ print(ex)
158
+ raise ex
130
159
  message = f"🚀 Streamlit app is running @:\n1- http://{local_ip_v4}:{port}\n2- http://{computer_name}:{port}\n3- http://localhost:{port}"
131
160
  from rich.panel import Panel
132
161
  from rich import print as rprint
133
162
  rprint(Panel(message))
134
- exe = "streamlit run --server.address 0.0.0.0 --server.headless true"
163
+ exe = f"streamlit run --server.address 0.0.0.0 --server.headless true --server.port {port}"
135
164
  # exe = f"cd '{choice_file.parent}'; " + exe
136
165
  elif args.interactive is False: exe = "python"
137
166
  elif args.jupyter: exe = "jupyter-lab"
@@ -145,9 +174,8 @@ def main() -> None:
145
174
  raise NotImplementedError(f"File type {choice_file.suffix} not supported, in the sense that I don't know how to fire it.")
146
175
 
147
176
  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.
148
- assert choice_file.suffix == ".py", f"File must be a python file to be imported as a module. Got {choice_file.suffix}"
177
+ assert choice_file.suffix == ".py", f"File must be a python file to be imported as a module. Got {choice_file}"
149
178
  import_line = get_import_module_code(str(choice_file))
150
- repo_root = get_repo_root(str(choice_file))
151
179
  if repo_root is not None:
152
180
  repo_root_add = f"""sys.path.append(r'{repo_root}')"""
153
181
  else:
@@ -199,7 +227,7 @@ except ImportError as _ex:
199
227
  if args.holdDirectory:
200
228
  command = f"{exe} {choice_file}"
201
229
  else:
202
- command = f"cd {choice_file.parent}\n\n{exe} {choice_file.name}\n\ncd {P.cwd()}"
230
+ command = f"cd {choice_file.parent}\n{exe} {choice_file.name}\ncd {P.cwd()}"
203
231
 
204
232
  elif args.cmd:
205
233
  command = rf""" cd /d {choice_file.parent} & {exe} {choice_file.name} """
@@ -208,21 +236,22 @@ except ImportError as _ex:
208
236
  kwargs_raw = " ".join(args.kw) if args.kw is not None else ""
209
237
  command = f"{exe} {choice_file} {kwargs_raw}"
210
238
  else:
211
- # command = f"cd {choice_file.parent}\n\n{exe} {choice_file.name}\n\ncd {P.cwd()}"
239
+ # command = f"cd {choice_file.parent}\n{exe} {choice_file.name}\ncd {P.cwd()}"
212
240
  command = f"{exe} {choice_file} "
213
241
  # this installs in ve env, which is not execution env
214
242
  # if "ipdb" in command: install_n_import("ipdb")
215
243
  # if "pudb" in command: install_n_import("pudb")
216
244
 
217
245
  if not args.cmd:
218
- if "ipdb" in command: command = f"pip install ipdb\n\n{command}"
219
- if "pudb" in command: command = f"pip install pudb\n\n{command}"
220
- command = f"{activate_ve_line}\n\n{command}"
246
+ if "ipdb" in command: command = f"pip install ipdb\n{command}"
247
+ if "pudb" in command: command = f"pip install pudb\n{command}"
248
+ command = f"{activate_ve_line}\n{command}"
221
249
  else:
222
250
  # CMD equivalent
223
251
  if "ipdb" in command: command = f"pip install ipdb & {command}"
224
252
  if "pudb" in command: command = f"pip install pudb & {command}"
225
- command = fr"""start cmd -Argument "/k %USERPROFILE%\venvs\{args.ve}\Scripts\activate.bat & {command} " """ # this works from powershell
253
+ new_line = "\n"
254
+ command = fr"""start cmd -Argument "/k {activate_ve_line.replace(".ps1", ".bat").replace(". ", "")} & {command.replace(new_line, " & ")} " """ # this works from powershell
226
255
  # 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)
227
256
 
228
257
  if args.submit_to_cloud:
@@ -235,9 +264,6 @@ python -m machineconfig.cluster.templates.cli_click --file {choice_file} """
235
264
  # try: install_n_import("clipboard").copy(command)
236
265
  # except Exception as ex: print(f"Failed to copy command to clipboard. {ex}")
237
266
 
238
- if args.loop:
239
- command = command + "\n" + f". {PROGRAM_PATH}"
240
-
241
267
  if args.Nprocess > 1:
242
268
  lines = [f""" zellij action new-tab --name nProcess{randstr(2)}"""]
243
269
  command = command.replace(". activate_ve", ". $HOME/scripts/activate_ve")
@@ -287,10 +313,32 @@ echo "Sleep 2 seconds to allow zellij to close the pane"
287
313
  sleep 1
288
314
  zellij action close-pane; sleep 2
289
315
  """
290
- if args.git_pull:
291
- command = f"\ngit -C {choice_file.parent} pull\n\n" + command
292
- console.print(Panel(Syntax(command, lexer="shell"), title=f"🔥 fire command @ {PROGRAM_PATH}: "), style="bold red")
293
- PROGRAM_PATH.write_text(command)
316
+ if args.watch: command = "watchexec --restart --exts py,sh,ps1 " + command
317
+ if args.git_pull: command = f"\ngit -C {choice_file.parent} pull\n" + command
318
+ if args.PathExport:
319
+ if platform.system() == "Linux": export_line = f"""export PYTHONPATH="{repo_root}""" + """:${PYTHONPATH}" """
320
+ elif platform.system() == "Windows":
321
+ # export_line = f"""set PYTHONPATH="{repo_root}""" + """:%PYTHONPATH%" """
322
+ # powershell equivalent
323
+ export_line = f"""$env:PYTHONPATH="{repo_root}""" + """:$env:PYTHONPATH" """
324
+ else:
325
+ raise NotImplementedError(f"Platform {platform.system()} not supported.")
326
+ command = export_line + "\n" + command
327
+
328
+ program_path = os.environ.get("op_script", None)
329
+ program_path = P(program_path) if program_path is not None else PROGRAM_PATH
330
+ if args.loop:
331
+ if platform.system() == "Linux":
332
+ command = command + "\nsleep 0.5"
333
+ elif platform.system() == "Windows":
334
+ # command = command + "timeout 0.5\n"
335
+ #pwsh equivalent
336
+ command ="$ErrorActionPreference = 'SilentlyContinue';\n" + command + "\nStart-Sleep -Seconds 0.5"
337
+ else:
338
+ raise NotImplementedError(f"Platform {platform.system()} not supported.")
339
+ command = command + f"\n. {program_path}"
340
+ console.print(Panel(Syntax(command, lexer="shell"), title=f"🔥 fire command @ {program_path}: "), style="bold red")
341
+ program_path.write_text(command)
294
342
 
295
343
 
296
344
  if __name__ == '__main__':
@@ -1,4 +1,3 @@
1
-
2
1
  from crocodile.core import Struct
3
2
  from crocodile.file_management import P, Read
4
3
  from pydantic import ConfigDict
@@ -6,6 +5,12 @@ from pydantic.dataclasses import dataclass
6
5
  from typing import Optional
7
6
  import os
8
7
  from machineconfig.utils.utils import DEFAULTS_PATH
8
+ from rich.console import Console
9
+ from rich.panel import Panel
10
+ from rich import box # Import box
11
+
12
+
13
+ console = Console()
9
14
 
10
15
 
11
16
  class ArgsDefaults:
@@ -42,32 +47,21 @@ class Args():
42
47
 
43
48
  @staticmethod
44
49
  def from_config(config_path: P):
45
- # from crocodile.core import install_n_import
46
- # install_n_import("pydantic")
47
- # from pydantic import BaseModel, ConfigDict
48
50
  return Args(**Read.json(config_path))
49
51
 
50
52
 
51
53
  def find_cloud_config(path: P):
52
- print(f"""
53
- ╭{'─' * 70}╮
54
- │ 🔍 Searching for cloud configuration file... │
55
- ╰{'─' * 70}╯
56
- """)
54
+ display_header(f"Searching for cloud configuration file @ {path}")
57
55
 
58
56
  for _i in range(len(path.parts)):
59
57
  if path.joinpath("cloud.json").exists():
60
58
  res = Args.from_config(path.joinpath("cloud.json"))
61
- print(f"""
62
- ╭{'─' * 70}╮
63
- │ ✅ Found cloud config at: {path.joinpath('cloud.json')} │
64
- ╰{'─' * 70}╯
65
- """)
59
+ display_success(f"Found cloud config at: {path.joinpath('cloud.json')}")
66
60
  Struct(res.__dict__).print(as_config=True, title="Cloud Config")
67
61
  return res
68
62
  path = path.parent
69
63
 
70
- print("No cloud configuration file found")
64
+ display_error("No cloud configuration file found")
71
65
  return None
72
66
 
73
67
 
@@ -76,30 +70,22 @@ def absolute(path: str) -> P:
76
70
  if not path.startswith(".") and obj.exists(): return obj
77
71
  try_absing = P.cwd().joinpath(path)
78
72
  if try_absing.exists(): return try_absing
79
- print(f"""
80
- ╭{'─' * 70}╮
81
- │ ⚠️ WARNING: │
82
- │ Path {path} could not be resolved to absolute path.
83
- │ Trying to resolve symlinks (this may result in unintended paths). │
84
- ╰{'─' * 70}╯
85
- """)
73
+ display_warning(f"Path {path} could not be resolved to absolute path.")
74
+ display_warning("Trying to resolve symlinks (this may result in unintended paths).")
86
75
  return obj.absolute()
87
76
 
88
77
 
89
78
 
90
79
  def get_secure_share_cloud_config(interactive: bool, cloud: Optional[str]) -> Args:
91
- print(f"""
92
- ╔{'═' * 70}╗
93
- ║ 🔐 Secure Share Cloud Configuration ║
94
- ╚{'═' * 70}╝
95
- """)
80
+ console = Console()
81
+ console.print(Panel("🔐 Secure Share Cloud Configuration", expand=False))
96
82
 
97
83
  if cloud is None:
98
84
  if os.environ.get("CLOUD_CONFIG_NAME") is not None:
99
85
  default_cloud = os.environ.get("CLOUD_CONFIG_NAME")
100
86
  assert default_cloud is not None
101
87
  cloud = default_cloud
102
- print(f"☁️ Using cloud from environment: {cloud}")
88
+ console.print(f"☁️ Using cloud from environment: {cloud}")
103
89
  else:
104
90
  try:
105
91
  default_cloud__ = Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
@@ -110,7 +96,7 @@ def get_secure_share_cloud_config(interactive: bool, cloud: Optional[str]) -> Ar
110
96
  cloud = input(f"☁️ Enter cloud name (default {default_cloud__}): ") or default_cloud__
111
97
  else:
112
98
  cloud = default_cloud__
113
- print(f"☁️ Using default cloud: {cloud}")
99
+ console.print(f"☁️ Using default cloud: {cloud}")
114
100
 
115
101
  default_password_path = P.home().joinpath("dotfiles/creds/passwords/quick_password")
116
102
  if default_password_path.exists():
@@ -125,10 +111,27 @@ def get_secure_share_cloud_config(interactive: bool, cloud: Optional[str]) -> Ar
125
111
  zip=True, overwrite=True, share=True,
126
112
  rel2home=True, root="myshare", os_specific=False,)
127
113
 
128
- print(f"""
129
- ╭{'─' * 70}╮
130
- │ ⚙️ Using SecureShare cloud config │
131
- ╰{'─' * 70}╯
132
- """)
114
+ display_success("Using SecureShare cloud config")
133
115
  Struct(res.__dict__).print(as_config=True, title="SecureShare Config")
134
116
  return res
117
+
118
+ def display_header(title: str):
119
+ console.print(Panel(title, box=box.DOUBLE_EDGE, title_align="left")) # Replace print with Panel
120
+
121
+ def display_subheader(title: str):
122
+ console.print(Panel(title, box=box.ROUNDED, title_align="left")) # Replace print with Panel
123
+
124
+ def display_content(content: str):
125
+ console.print(Panel(content, box=box.ROUNDED, title_align="left")) # Replace print with Panel
126
+
127
+ def display_status(status: str):
128
+ console.print(Panel(status, box=box.ROUNDED, title_align="left")) # Replace print with Panel
129
+
130
+ def display_success(message: str):
131
+ console.print(Panel(message, box=box.ROUNDED, border_style="green", title_align="left")) # Replace print with Panel
132
+
133
+ def display_warning(message: str):
134
+ console.print(Panel(message, box=box.ROUNDED, border_style="yellow", title_align="left")) # Replace print with Panel
135
+
136
+ def display_error(message: str):
137
+ console.print(Panel(message, box=box.ROUNDED, border_style="red", title_align="left")) # Replace print with Panel