machineconfig 2.0__py3-none-any.whl → 2.2__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 (253) hide show
  1. machineconfig/cluster/cloud_manager.py +0 -3
  2. machineconfig/cluster/data_transfer.py +0 -1
  3. machineconfig/cluster/file_manager.py +0 -1
  4. machineconfig/cluster/job_params.py +0 -3
  5. machineconfig/cluster/loader_runner.py +0 -3
  6. machineconfig/cluster/remote_machine.py +0 -1
  7. machineconfig/cluster/script_notify_upon_completion.py +0 -1
  8. machineconfig/cluster/sessions_managers/archive/create_zellij_template.py +5 -6
  9. machineconfig/cluster/sessions_managers/archive/session_managers.py +0 -1
  10. machineconfig/cluster/sessions_managers/enhanced_command_runner.py +17 -57
  11. machineconfig/cluster/sessions_managers/wt_local.py +36 -110
  12. machineconfig/cluster/sessions_managers/wt_local_manager.py +42 -112
  13. machineconfig/cluster/sessions_managers/wt_remote.py +23 -30
  14. machineconfig/cluster/sessions_managers/wt_remote_manager.py +20 -62
  15. machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +10 -15
  16. machineconfig/cluster/sessions_managers/wt_utils/process_monitor.py +27 -127
  17. machineconfig/cluster/sessions_managers/wt_utils/remote_executor.py +10 -43
  18. machineconfig/cluster/sessions_managers/wt_utils/session_manager.py +22 -101
  19. machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +11 -39
  20. machineconfig/cluster/sessions_managers/zellij_local.py +49 -102
  21. machineconfig/cluster/sessions_managers/zellij_local_manager.py +34 -78
  22. machineconfig/cluster/sessions_managers/zellij_remote.py +17 -24
  23. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +7 -13
  24. machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +4 -2
  25. machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +6 -6
  26. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +18 -88
  27. machineconfig/cluster/sessions_managers/zellij_utils/remote_executor.py +2 -6
  28. machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +12 -40
  29. machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +3 -2
  30. machineconfig/cluster/templates/cli_click.py +0 -1
  31. machineconfig/cluster/templates/cli_gooey.py +0 -2
  32. machineconfig/cluster/templates/cli_trogon.py +0 -1
  33. machineconfig/cluster/templates/run_cloud.py +0 -1
  34. machineconfig/cluster/templates/run_cluster.py +0 -1
  35. machineconfig/cluster/templates/run_remote.py +0 -1
  36. machineconfig/cluster/templates/utils.py +27 -46
  37. machineconfig/jobs/__pycache__/__init__.cpython-313.pyc +0 -0
  38. machineconfig/jobs/linux/msc/cli_agents.sh +16 -0
  39. machineconfig/jobs/python/check_installations.py +2 -1
  40. machineconfig/jobs/python/create_bootable_media.py +0 -2
  41. machineconfig/jobs/python/python_ve_symlink.py +9 -11
  42. machineconfig/jobs/python/tasks.py +0 -1
  43. machineconfig/jobs/python/vscode/api.py +5 -5
  44. machineconfig/jobs/python/vscode/link_ve.py +13 -14
  45. machineconfig/jobs/python/vscode/select_interpreter.py +21 -22
  46. machineconfig/jobs/python/vscode/sync_code.py +9 -13
  47. machineconfig/jobs/python_custom_installers/archive/ngrok.py +13 -13
  48. machineconfig/jobs/python_custom_installers/dev/aider.py +7 -15
  49. machineconfig/jobs/python_custom_installers/dev/alacritty.py +9 -18
  50. machineconfig/jobs/python_custom_installers/dev/brave.py +10 -19
  51. machineconfig/jobs/python_custom_installers/dev/bypass_paywall.py +8 -15
  52. machineconfig/jobs/python_custom_installers/dev/code.py +12 -32
  53. machineconfig/jobs/python_custom_installers/dev/cursor.py +3 -14
  54. machineconfig/jobs/python_custom_installers/dev/docker_desktop.py +8 -7
  55. machineconfig/jobs/python_custom_installers/dev/espanso.py +15 -19
  56. machineconfig/jobs/python_custom_installers/dev/goes.py +5 -12
  57. machineconfig/jobs/python_custom_installers/dev/lvim.py +9 -17
  58. machineconfig/jobs/python_custom_installers/dev/nerdfont.py +12 -19
  59. machineconfig/jobs/python_custom_installers/dev/redis.py +12 -20
  60. machineconfig/jobs/python_custom_installers/dev/wezterm.py +12 -19
  61. machineconfig/jobs/python_custom_installers/dev/winget.py +5 -23
  62. machineconfig/jobs/python_custom_installers/docker.py +12 -21
  63. machineconfig/jobs/python_custom_installers/gh.py +11 -19
  64. machineconfig/jobs/python_custom_installers/hx.py +32 -16
  65. machineconfig/jobs/python_custom_installers/warp-cli.py +12 -20
  66. machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-313.pyc +0 -0
  67. machineconfig/jobs/python_generic_installers/config.json +1 -1
  68. machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-313.pyc +0 -0
  69. machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +1 -1
  70. machineconfig/jobs/windows/msc/cli_agents.bat +0 -0
  71. machineconfig/jobs/windows/msc/cli_agents.ps1 +0 -0
  72. machineconfig/jobs/windows/start_terminal.ps1 +1 -1
  73. machineconfig/profile/create.py +38 -26
  74. machineconfig/profile/create_hardlinks.py +29 -20
  75. machineconfig/profile/shell.py +56 -32
  76. machineconfig/scripts/__init__.py +0 -2
  77. machineconfig/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
  78. machineconfig/scripts/cloud/init.sh +2 -2
  79. machineconfig/scripts/linux/checkout_versions +1 -1
  80. machineconfig/scripts/linux/choose_wezterm_theme +1 -1
  81. machineconfig/scripts/linux/cloud_copy +1 -1
  82. machineconfig/scripts/linux/cloud_manager +1 -1
  83. machineconfig/scripts/linux/cloud_mount +1 -1
  84. machineconfig/scripts/linux/cloud_repo_sync +1 -1
  85. machineconfig/scripts/linux/cloud_sync +1 -1
  86. machineconfig/scripts/linux/croshell +1 -1
  87. machineconfig/scripts/linux/devops +7 -7
  88. machineconfig/scripts/linux/fire +1 -1
  89. machineconfig/scripts/linux/fire_agents +3 -2
  90. machineconfig/scripts/linux/ftpx +1 -1
  91. machineconfig/scripts/linux/gh_models +1 -1
  92. machineconfig/scripts/linux/kill_process +1 -1
  93. machineconfig/scripts/linux/mcinit +1 -1
  94. machineconfig/scripts/linux/repos +1 -1
  95. machineconfig/scripts/linux/scheduler +1 -1
  96. machineconfig/scripts/linux/start_slidev +1 -1
  97. machineconfig/scripts/linux/start_terminals +1 -1
  98. machineconfig/scripts/linux/url2md +1 -1
  99. machineconfig/scripts/linux/warp-cli.sh +122 -0
  100. machineconfig/scripts/linux/wifi_conn +1 -1
  101. machineconfig/scripts/python/__pycache__/__init__.cpython-313.pyc +0 -0
  102. machineconfig/scripts/python/__pycache__/devops.cpython-313.pyc +0 -0
  103. machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-313.pyc +0 -0
  104. machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-313.pyc +0 -0
  105. machineconfig/scripts/python/__pycache__/fire_agents.cpython-313.pyc +0 -0
  106. machineconfig/scripts/python/ai/__init__.py +0 -0
  107. machineconfig/scripts/python/ai/generate_files.py +83 -0
  108. machineconfig/scripts/python/ai/instructions/python/dev.instructions.md +2 -2
  109. machineconfig/scripts/python/ai/mcinit.py +14 -7
  110. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +10 -5
  111. machineconfig/scripts/python/archive/tmate_conn.py +5 -5
  112. machineconfig/scripts/python/archive/tmate_start.py +7 -7
  113. machineconfig/scripts/python/choose_wezterm_theme.py +35 -32
  114. machineconfig/scripts/python/cloud_copy.py +23 -14
  115. machineconfig/scripts/python/cloud_mount.py +36 -24
  116. machineconfig/scripts/python/cloud_repo_sync.py +40 -27
  117. machineconfig/scripts/python/cloud_sync.py +4 -4
  118. machineconfig/scripts/python/croshell.py +40 -29
  119. machineconfig/scripts/python/devops.py +45 -27
  120. machineconfig/scripts/python/devops_add_identity.py +15 -25
  121. machineconfig/scripts/python/devops_add_ssh_key.py +8 -8
  122. machineconfig/scripts/python/devops_backup_retrieve.py +18 -16
  123. machineconfig/scripts/python/devops_devapps_install.py +25 -20
  124. machineconfig/scripts/python/devops_update_repos.py +232 -59
  125. machineconfig/scripts/python/dotfile.py +17 -15
  126. machineconfig/scripts/python/fire_agents.py +48 -22
  127. machineconfig/scripts/python/fire_jobs.py +93 -58
  128. machineconfig/scripts/python/ftpx.py +26 -15
  129. machineconfig/scripts/python/get_zellij_cmd.py +8 -7
  130. machineconfig/scripts/python/helpers/cloud_helpers.py +33 -28
  131. machineconfig/scripts/python/helpers/helpers2.py +27 -16
  132. machineconfig/scripts/python/helpers/helpers4.py +45 -32
  133. machineconfig/scripts/python/helpers/helpers5.py +1 -1
  134. machineconfig/scripts/python/helpers/repo_sync_helpers.py +32 -10
  135. machineconfig/scripts/python/mount_nfs.py +9 -16
  136. machineconfig/scripts/python/mount_nw_drive.py +10 -5
  137. machineconfig/scripts/python/mount_ssh.py +9 -7
  138. machineconfig/scripts/python/repos.py +216 -58
  139. machineconfig/scripts/python/snapshot.py +0 -1
  140. machineconfig/scripts/python/start_slidev.py +11 -6
  141. machineconfig/scripts/python/start_terminals.py +22 -16
  142. machineconfig/scripts/python/viewer_template.py +0 -1
  143. machineconfig/scripts/python/wifi_conn.py +49 -75
  144. machineconfig/scripts/python/wsl_windows_transfer.py +9 -7
  145. machineconfig/scripts/windows/checkout_version.ps1 +1 -3
  146. machineconfig/scripts/windows/choose_wezterm_theme.ps1 +1 -3
  147. machineconfig/scripts/windows/cloud_copy.ps1 +2 -6
  148. machineconfig/scripts/windows/cloud_manager.ps1 +1 -1
  149. machineconfig/scripts/windows/cloud_repo_sync.ps1 +1 -2
  150. machineconfig/scripts/windows/cloud_sync.ps1 +2 -2
  151. machineconfig/scripts/windows/croshell.ps1 +2 -2
  152. machineconfig/scripts/windows/devops.ps1 +1 -4
  153. machineconfig/scripts/windows/dotfile.ps1 +1 -3
  154. machineconfig/scripts/windows/fire.ps1 +1 -1
  155. machineconfig/scripts/windows/ftpx.ps1 +2 -2
  156. machineconfig/scripts/windows/gpt.ps1 +1 -1
  157. machineconfig/scripts/windows/kill_process.ps1 +1 -2
  158. machineconfig/scripts/windows/mcinit.ps1 +1 -1
  159. machineconfig/scripts/windows/mount_nfs.ps1 +1 -1
  160. machineconfig/scripts/windows/mount_ssh.ps1 +1 -1
  161. machineconfig/scripts/windows/pomodoro.ps1 +1 -1
  162. machineconfig/scripts/windows/py2exe.ps1 +1 -3
  163. machineconfig/scripts/windows/repos.ps1 +1 -1
  164. machineconfig/scripts/windows/scheduler.ps1 +1 -1
  165. machineconfig/scripts/windows/snapshot.ps1 +2 -2
  166. machineconfig/scripts/windows/start_slidev.ps1 +1 -1
  167. machineconfig/scripts/windows/start_terminals.ps1 +1 -1
  168. machineconfig/scripts/windows/wifi_conn.ps1 +1 -1
  169. machineconfig/scripts/windows/wsl_windows_transfer.ps1 +1 -3
  170. machineconfig/settings/lf/linux/lfrc +2 -1
  171. machineconfig/settings/linters/.ruff_cache/.gitignore +2 -0
  172. machineconfig/settings/linters/.ruff_cache/CACHEDIR.TAG +1 -0
  173. machineconfig/settings/lvim/windows/archive/config_additional.lua +1 -1
  174. machineconfig/settings/svim/linux/init.toml +1 -1
  175. machineconfig/settings/svim/windows/init.toml +1 -1
  176. machineconfig/setup_linux/web_shortcuts/croshell.sh +3 -52
  177. machineconfig/setup_linux/web_shortcuts/interactive.sh +6 -6
  178. machineconfig/setup_linux/web_shortcuts/ssh.sh +0 -4
  179. machineconfig/setup_windows/web_shortcuts/all.ps1 +2 -2
  180. machineconfig/setup_windows/web_shortcuts/ascii_art.ps1 +1 -1
  181. machineconfig/setup_windows/web_shortcuts/croshell.ps1 +1 -1
  182. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +5 -5
  183. machineconfig/setup_windows/wt_and_pwsh/install_fonts.ps1 +51 -15
  184. machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +58 -13
  185. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +45 -37
  186. machineconfig/utils/ai/generate_file_checklist.py +8 -10
  187. machineconfig/utils/ai/url2md.py +4 -2
  188. machineconfig/utils/cloud/onedrive/setup_oauth.py +1 -0
  189. machineconfig/utils/cloud/onedrive/transaction.py +63 -98
  190. machineconfig/utils/code.py +62 -41
  191. machineconfig/utils/installer.py +29 -35
  192. machineconfig/utils/installer_utils/installer_abc.py +11 -11
  193. machineconfig/utils/installer_utils/installer_class.py +155 -74
  194. machineconfig/utils/links.py +112 -31
  195. machineconfig/utils/notifications.py +211 -0
  196. machineconfig/utils/options.py +41 -42
  197. machineconfig/utils/path.py +13 -6
  198. machineconfig/utils/path_reduced.py +614 -311
  199. machineconfig/utils/procs.py +48 -42
  200. machineconfig/utils/scheduling.py +0 -1
  201. machineconfig/utils/source_of_truth.py +27 -0
  202. machineconfig/utils/ssh.py +146 -85
  203. machineconfig/utils/terminal.py +84 -37
  204. machineconfig/utils/upgrade_packages.py +91 -0
  205. machineconfig/utils/utils2.py +39 -50
  206. machineconfig/utils/utils5.py +195 -116
  207. machineconfig/utils/ve.py +13 -5
  208. {machineconfig-2.0.dist-info → machineconfig-2.2.dist-info}/METADATA +14 -13
  209. {machineconfig-2.0.dist-info → machineconfig-2.2.dist-info}/RECORD +212 -237
  210. machineconfig/jobs/__pycache__/__init__.cpython-311.pyc +0 -0
  211. machineconfig/jobs/python/__pycache__/__init__.cpython-311.pyc +0 -0
  212. machineconfig/jobs/python/__pycache__/python_ve_symlink.cpython-311.pyc +0 -0
  213. machineconfig/jobs/python/archive/python_tools.txt +0 -12
  214. machineconfig/jobs/python/vscode/__pycache__/select_interpreter.cpython-311.pyc +0 -0
  215. machineconfig/jobs/python_custom_installers/__pycache__/__init__.cpython-311.pyc +0 -0
  216. machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-311.pyc +0 -0
  217. machineconfig/jobs/python_generic_installers/update.py +0 -3
  218. machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-311.pyc +0 -0
  219. machineconfig/profile/__pycache__/__init__.cpython-311.pyc +0 -0
  220. machineconfig/profile/__pycache__/create.cpython-311.pyc +0 -0
  221. machineconfig/profile/__pycache__/shell.cpython-311.pyc +0 -0
  222. machineconfig/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  223. machineconfig/scripts/linux/activate_ve +0 -87
  224. machineconfig/scripts/python/__pycache__/__init__.cpython-311.pyc +0 -0
  225. machineconfig/scripts/python/__pycache__/cloud_copy.cpython-311.pyc +0 -0
  226. machineconfig/scripts/python/__pycache__/cloud_mount.cpython-311.pyc +0 -0
  227. machineconfig/scripts/python/__pycache__/cloud_sync.cpython-311.pyc +0 -0
  228. machineconfig/scripts/python/__pycache__/croshell.cpython-311.pyc +0 -0
  229. machineconfig/scripts/python/__pycache__/devops.cpython-311.pyc +0 -0
  230. machineconfig/scripts/python/__pycache__/devops_backup_retrieve.cpython-311.pyc +0 -0
  231. machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-311.pyc +0 -0
  232. machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-311.pyc +0 -0
  233. machineconfig/scripts/python/__pycache__/fire_agents.cpython-311.pyc +0 -0
  234. machineconfig/scripts/python/__pycache__/fire_jobs.cpython-311.pyc +0 -0
  235. machineconfig/scripts/python/__pycache__/fire_jobs.cpython-313.pyc +0 -0
  236. machineconfig/scripts/python/__pycache__/get_zellij_cmd.cpython-311.pyc +0 -0
  237. machineconfig/scripts/python/__pycache__/repos.cpython-311.pyc +0 -0
  238. machineconfig/scripts/python/ai/__pycache__/init.cpython-311.pyc +0 -0
  239. machineconfig/scripts/python/ai/__pycache__/mcinit.cpython-311.pyc +0 -0
  240. machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-311.pyc +0 -0
  241. machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-313.pyc +0 -0
  242. machineconfig/scripts/python/helpers/__pycache__/cloud_helpers.cpython-311.pyc +0 -0
  243. machineconfig/scripts/python/helpers/__pycache__/helpers2.cpython-311.pyc +0 -0
  244. machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-311.pyc +0 -0
  245. machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-313.pyc +0 -0
  246. machineconfig/scripts/python/helpers/__pycache__/repo_sync_helpers.cpython-311.pyc +0 -0
  247. machineconfig/scripts/windows/activate_ve.ps1 +0 -54
  248. machineconfig/setup_linux/web_shortcuts/all.sh +0 -48
  249. machineconfig/setup_linux/web_shortcuts/update_system.sh +0 -48
  250. machineconfig/utils/utils.py +0 -95
  251. /machineconfig/setup_linux/web_shortcuts/{tmp.sh → android.sh} +0 -0
  252. {machineconfig-2.0.dist-info → machineconfig-2.2.dist-info}/WHEEL +0 -0
  253. {machineconfig-2.0.dist-info → machineconfig-2.2.dist-info}/top_level.txt +0 -0
@@ -43,12 +43,14 @@ import json
43
43
 
44
44
  def get_rclone_token(section: str):
45
45
  import platform
46
+
46
47
  if platform.system() == "Windows":
47
48
  rclone_file_path = Path(os.getenv("APPDATA", "")) / "rclone" / "rclone.conf"
48
49
  else:
49
50
  rclone_file_path = Path.home() / ".config" / "rclone" / "rclone.conf"
50
51
  if rclone_file_path.exists():
51
52
  import configparser
53
+
52
54
  config = configparser.ConfigParser()
53
55
  config.read(rclone_file_path)
54
56
  if section in config:
@@ -57,9 +59,11 @@ def get_rclone_token(section: str):
57
59
  return dict(results)
58
60
  return None
59
61
 
62
+
60
63
  # Configuration - Will be loaded from rclone config
61
64
  _cached_config = None
62
65
 
66
+
63
67
  def get_config(section: str = "odp") -> dict[str, Any]:
64
68
  """
65
69
  Get OneDrive configuration from rclone config.
@@ -83,31 +87,32 @@ def get_config(section: str = "odp") -> dict[str, Any]:
83
87
  except json.JSONDecodeError:
84
88
  raise Exception(f"Invalid token format in rclone config section '{section}'")
85
89
 
86
- _cached_config = {
87
- "token": token_data,
88
- "drive_id": rclone_config.get("drive_id"),
89
- "drive_type": rclone_config.get("drive_type", "personal")
90
- }
90
+ _cached_config = {"token": token_data, "drive_id": rclone_config.get("drive_id"), "drive_type": rclone_config.get("drive_type", "personal")}
91
91
 
92
92
  return _cached_config
93
93
 
94
+
94
95
  def get_token() -> dict[str, Any]:
95
96
  """Get the current token from rclone config."""
96
97
  return get_config()["token"]
97
98
 
99
+
98
100
  def get_drive_id():
99
101
  """Get the drive ID from rclone config."""
100
102
  return get_config()["drive_id"]
101
103
 
104
+
102
105
  def get_drive_type():
103
106
  """Get the drive type from rclone config."""
104
107
  return get_config()["drive_type"]
105
108
 
109
+
106
110
  def clear_config_cache():
107
111
  """Clear the cached config to force reload from rclone."""
108
112
  global _cached_config
109
113
  _cached_config = None
110
114
 
115
+
111
116
  # OAuth2 Configuration - You'll need to set these up in Azure App Registration
112
117
  CLIENT_ID = os.getenv("ONEDRIVE_CLIENT_ID", "your_client_id_here")
113
118
  CLIENT_SECRET = os.getenv("ONEDRIVE_CLIENT_SECRET", "your_client_secret_here") # Optional for public clients
@@ -133,10 +138,10 @@ def is_token_valid() -> bool:
133
138
  return False
134
139
 
135
140
  # Remove timezone info for parsing (rclone format includes timezone)
136
- if '+' in expiry_str:
137
- expiry_str = expiry_str.split('+')[0]
138
- elif 'Z' in expiry_str:
139
- expiry_str = expiry_str.replace('Z', '')
141
+ if "+" in expiry_str:
142
+ expiry_str = expiry_str.split("+")[0]
143
+ elif "Z" in expiry_str:
144
+ expiry_str = expiry_str.replace("Z", "")
140
145
 
141
146
  expiry_time = datetime.fromisoformat(expiry_str)
142
147
  current_time = datetime.now()
@@ -195,9 +200,9 @@ def make_graph_request(method: str, endpoint: str, **kwargs: Any) -> requests.Re
195
200
  if not token:
196
201
  raise Exception("Failed to get valid access token")
197
202
 
198
- headers = kwargs.get('headers', {})
199
- headers['Authorization'] = f'Bearer {token}'
200
- kwargs['headers'] = headers
203
+ headers = kwargs.get("headers", {})
204
+ headers["Authorization"] = f"Bearer {token}"
205
+ kwargs["headers"] = headers
201
206
 
202
207
  url = f"{GRAPH_API_BASE}/{endpoint.lstrip('/')}"
203
208
  response = requests.request(method, url, **kwargs)
@@ -228,12 +233,12 @@ def push_to_onedrive(local_path: str, remote_path: str) -> bool:
228
233
  return False
229
234
 
230
235
  # Ensure remote path starts with /
231
- if not remote_path.startswith('/'):
232
- remote_path = '/' + remote_path
236
+ if not remote_path.startswith("/"):
237
+ remote_path = "/" + remote_path
233
238
 
234
239
  # Create parent directories if they don't exist
235
240
  remote_dir = os.path.dirname(remote_path)
236
- if remote_dir and remote_dir != '/':
241
+ if remote_dir and remote_dir != "/":
237
242
  create_remote_directory(remote_dir)
238
243
 
239
244
  try:
@@ -253,15 +258,15 @@ def push_to_onedrive(local_path: str, remote_path: str) -> bool:
253
258
  def simple_upload(local_file: Path, remote_path: str) -> bool:
254
259
  """Upload small files using simple upload."""
255
260
  try:
256
- with open(local_file, 'rb') as f:
261
+ with open(local_file, "rb") as f:
257
262
  file_content = f.read()
258
263
 
259
264
  # URL encode the remote path and use specific drive
260
- encoded_path = quote(remote_path, safe='/')
265
+ encoded_path = quote(remote_path, safe="/")
261
266
  drive_id = get_drive_id()
262
267
  endpoint = f"drives/{drive_id}/root:{encoded_path}:/content"
263
268
 
264
- response = make_graph_request('PUT', endpoint, data=file_content)
269
+ response = make_graph_request("PUT", endpoint, data=file_content)
265
270
 
266
271
  if response.status_code in [200, 201]:
267
272
  print(f"Successfully uploaded: {local_file} -> {remote_path}")
@@ -279,28 +284,23 @@ def resumable_upload(local_file: Path, remote_path: str) -> bool:
279
284
  """Upload large files using resumable upload."""
280
285
  try:
281
286
  # Create upload session using specific drive
282
- encoded_path = quote(remote_path, safe='/')
287
+ encoded_path = quote(remote_path, safe="/")
283
288
  drive_id = get_drive_id()
284
289
  endpoint = f"drives/{drive_id}/root:{encoded_path}:/createUploadSession"
285
290
 
286
- item_data = {
287
- "item": {
288
- "@microsoft.graph.conflictBehavior": "replace",
289
- "name": local_file.name
290
- }
291
- }
291
+ item_data = {"item": {"@microsoft.graph.conflictBehavior": "replace", "name": local_file.name}}
292
292
 
293
- response = make_graph_request('POST', endpoint, json=item_data)
293
+ response = make_graph_request("POST", endpoint, json=item_data)
294
294
 
295
295
  if response.status_code != 200:
296
296
  print(f"Failed to create upload session: {response.status_code} - {response.text}")
297
297
  return False
298
298
 
299
- upload_url = response.json()['uploadUrl']
299
+ upload_url = response.json()["uploadUrl"]
300
300
  file_size = local_file.stat().st_size
301
301
  chunk_size = 320 * 1024 # 320KB chunks
302
302
 
303
- with open(local_file, 'rb') as f:
303
+ with open(local_file, "rb") as f:
304
304
  bytes_uploaded = 0
305
305
 
306
306
  while bytes_uploaded < file_size:
@@ -310,10 +310,7 @@ def resumable_upload(local_file: Path, remote_path: str) -> bool:
310
310
 
311
311
  chunk_end = min(bytes_uploaded + len(chunk_data) - 1, file_size - 1)
312
312
 
313
- headers = {
314
- 'Content-Range': f'bytes {bytes_uploaded}-{chunk_end}/{file_size}',
315
- 'Content-Length': str(len(chunk_data))
316
- }
313
+ headers = {"Content-Range": f"bytes {bytes_uploaded}-{chunk_end}/{file_size}", "Content-Length": str(len(chunk_data))}
317
314
 
318
315
  chunk_response = requests.put(upload_url, data=chunk_data, headers=headers)
319
316
 
@@ -345,16 +342,16 @@ def pull_from_onedrive(remote_path: str, local_path: str) -> bool:
345
342
  True if successful, False otherwise
346
343
  """
347
344
  # Ensure remote path starts with /
348
- if not remote_path.startswith('/'):
349
- remote_path = '/' + remote_path
345
+ if not remote_path.startswith("/"):
346
+ remote_path = "/" + remote_path
350
347
 
351
348
  try:
352
349
  # Get file metadata and download URL using specific drive
353
- encoded_path = quote(remote_path, safe='/')
350
+ encoded_path = quote(remote_path, safe="/")
354
351
  drive_id = get_drive_id()
355
352
  endpoint = f"drives/{drive_id}/root:{encoded_path}"
356
353
 
357
- response = make_graph_request('GET', endpoint)
354
+ response = make_graph_request("GET", endpoint)
358
355
 
359
356
  if response.status_code == 404:
360
357
  print(f"File not found in OneDrive: {remote_path}")
@@ -366,12 +363,12 @@ def pull_from_onedrive(remote_path: str, local_path: str) -> bool:
366
363
  file_info = response.json()
367
364
 
368
365
  # Check if it's a file (not a folder)
369
- if 'folder' in file_info:
366
+ if "folder" in file_info:
370
367
  print(f"Path is a folder, not a file: {remote_path}")
371
368
  return False
372
369
 
373
370
  # Get download URL
374
- download_url = file_info.get('@microsoft.graph.downloadUrl')
371
+ download_url = file_info.get("@microsoft.graph.downloadUrl")
375
372
  if not download_url:
376
373
  print("No download URL available")
377
374
  return False
@@ -384,10 +381,10 @@ def pull_from_onedrive(remote_path: str, local_path: str) -> bool:
384
381
  download_response = requests.get(download_url, stream=True)
385
382
  download_response.raise_for_status()
386
383
 
387
- file_size = int(file_info.get('size', 0))
384
+ file_size = int(file_info.get("size", 0))
388
385
  bytes_downloaded = 0
389
386
 
390
- with open(local_file, 'wb') as f:
387
+ with open(local_file, "wb") as f:
391
388
  for chunk in download_response.iter_content(chunk_size=8192):
392
389
  if chunk:
393
390
  f.write(chunk)
@@ -415,20 +412,20 @@ def create_remote_directory(remote_path: str) -> bool:
415
412
  Returns:
416
413
  True if successful or already exists, False otherwise
417
414
  """
418
- if not remote_path or remote_path == '/':
415
+ if not remote_path or remote_path == "/":
419
416
  return True
420
417
 
421
418
  # Ensure remote path starts with /
422
- if not remote_path.startswith('/'):
423
- remote_path = '/' + remote_path
419
+ if not remote_path.startswith("/"):
420
+ remote_path = "/" + remote_path
424
421
 
425
422
  try:
426
423
  # Check if directory already exists using specific drive
427
- encoded_path = quote(remote_path, safe='/')
424
+ encoded_path = quote(remote_path, safe="/")
428
425
  drive_id = get_drive_id()
429
426
  endpoint = f"drives/{drive_id}/root:{encoded_path}"
430
427
 
431
- response = make_graph_request('GET', endpoint)
428
+ response = make_graph_request("GET", endpoint)
432
429
 
433
430
  if response.status_code == 200:
434
431
  # Directory already exists
@@ -439,26 +436,22 @@ def create_remote_directory(remote_path: str) -> bool:
439
436
 
440
437
  # Create parent directory first
441
438
  parent_dir = os.path.dirname(remote_path)
442
- if parent_dir and parent_dir != '/':
439
+ if parent_dir and parent_dir != "/":
443
440
  if not create_remote_directory(parent_dir):
444
441
  return False
445
442
 
446
443
  # Create the directory
447
444
  dir_name = os.path.basename(remote_path)
448
- parent_encoded = quote(parent_dir if parent_dir else '/', safe='/')
445
+ parent_encoded = quote(parent_dir if parent_dir else "/", safe="/")
449
446
 
450
- if parent_dir and parent_dir != '/':
447
+ if parent_dir and parent_dir != "/":
451
448
  endpoint = f"drives/{drive_id}/root:{parent_encoded}:/children"
452
449
  else:
453
450
  endpoint = f"drives/{drive_id}/root/children"
454
451
 
455
- folder_data = {
456
- "name": dir_name,
457
- "folder": {},
458
- "@microsoft.graph.conflictBehavior": "replace"
459
- }
452
+ folder_data = {"name": dir_name, "folder": {}, "@microsoft.graph.conflictBehavior": "replace"}
460
453
 
461
- response = make_graph_request('POST', endpoint, json=folder_data)
454
+ response = make_graph_request("POST", endpoint, json=folder_data)
462
455
 
463
456
  if response.status_code in [200, 201]:
464
457
  return True
@@ -487,20 +480,13 @@ def refresh_access_token() -> Optional[dict[str, Any]]:
487
480
  print("🔄 Refreshing access token...")
488
481
 
489
482
  # Prepare the token refresh request
490
- data = {
491
- 'client_id': CLIENT_ID,
492
- 'grant_type': 'refresh_token',
493
- 'refresh_token': refresh_token,
494
- 'scope': 'https://graph.microsoft.com/Files.ReadWrite.All offline_access'
495
- }
483
+ data = {"client_id": CLIENT_ID, "grant_type": "refresh_token", "refresh_token": refresh_token, "scope": "https://graph.microsoft.com/Files.ReadWrite.All offline_access"}
496
484
 
497
485
  # Add client secret if available (for confidential clients)
498
486
  if CLIENT_SECRET and CLIENT_SECRET != "your_client_secret_here":
499
- data['client_secret'] = CLIENT_SECRET
487
+ data["client_secret"] = CLIENT_SECRET
500
488
 
501
- headers = {
502
- 'Content-Type': 'application/x-www-form-urlencoded'
503
- }
489
+ headers = {"Content-Type": "application/x-www-form-urlencoded"}
504
490
 
505
491
  try:
506
492
  response = requests.post(OAUTH_TOKEN_ENDPOINT, data=data, headers=headers)
@@ -509,15 +495,15 @@ def refresh_access_token() -> Optional[dict[str, Any]]:
509
495
  token_data = response.json()
510
496
 
511
497
  # Calculate expiry time (tokens typically last 1 hour)
512
- expires_in = token_data.get('expires_in', 3600) # Default to 1 hour
498
+ expires_in = token_data.get("expires_in", 3600) # Default to 1 hour
513
499
  expiry_time = datetime.now() + timedelta(seconds=expires_in)
514
500
 
515
501
  # Update the cached token configuration
516
502
  new_token = {
517
- 'access_token': token_data['access_token'],
518
- 'token_type': token_data.get('token_type', 'Bearer'),
519
- 'refresh_token': token_data.get('refresh_token', refresh_token), # Use new or keep old
520
- 'expiry': expiry_time.isoformat()
503
+ "access_token": token_data["access_token"],
504
+ "token_type": token_data.get("token_type", "Bearer"),
505
+ "refresh_token": token_data.get("refresh_token", refresh_token), # Use new or keep old
506
+ "expiry": expiry_time.isoformat(),
521
507
  }
522
508
 
523
509
  # Update the cached config
@@ -564,7 +550,7 @@ def save_token_to_file(token_data: dict[str, Any], file_path: Optional[str] = No
564
550
  # Create directory if it doesn't exist
565
551
  os.makedirs(os.path.dirname(file_path), exist_ok=True)
566
552
 
567
- with open(file_path, 'w') as f:
553
+ with open(file_path, "w") as f:
568
554
  json.dump(token_data, f, indent=2)
569
555
 
570
556
  # Set restrictive permissions (readable only by owner)
@@ -593,7 +579,7 @@ def load_token_from_file(file_path: Optional[str] = None) -> Optional[dict[str,
593
579
 
594
580
  try:
595
581
  if os.path.exists(file_path):
596
- with open(file_path, 'r') as f:
582
+ with open(file_path, "r") as f:
597
583
  token_data = json.load(f)
598
584
 
599
585
  # Update the cached config token
@@ -624,14 +610,7 @@ def get_authorization_url() -> str:
624
610
  """
625
611
  from urllib.parse import urlencode
626
612
 
627
- params = {
628
- 'client_id': CLIENT_ID,
629
- 'response_type': 'code',
630
- 'redirect_uri': REDIRECT_URI,
631
- 'response_mode': 'query',
632
- 'scope': 'https://graph.microsoft.com/Files.ReadWrite.All offline_access',
633
- 'state': 'onedrive_auth'
634
- }
613
+ params = {"client_id": CLIENT_ID, "response_type": "code", "redirect_uri": REDIRECT_URI, "response_mode": "query", "scope": "https://graph.microsoft.com/Files.ReadWrite.All offline_access", "state": "onedrive_auth"}
635
614
 
636
615
  auth_url = f"https://login.microsoftonline.com/common/oauth2/v2.0/authorize?{urlencode(params)}"
637
616
  return auth_url
@@ -648,21 +627,13 @@ def exchange_authorization_code(authorization_code: str) -> Optional[dict[str, A
648
627
  Returns:
649
628
  Token dictionary or None if failed
650
629
  """
651
- data = {
652
- 'client_id': CLIENT_ID,
653
- 'grant_type': 'authorization_code',
654
- 'code': authorization_code,
655
- 'redirect_uri': REDIRECT_URI,
656
- 'scope': 'https://graph.microsoft.com/Files.ReadWrite.All offline_access'
657
- }
630
+ data = {"client_id": CLIENT_ID, "grant_type": "authorization_code", "code": authorization_code, "redirect_uri": REDIRECT_URI, "scope": "https://graph.microsoft.com/Files.ReadWrite.All offline_access"}
658
631
 
659
632
  # Add client secret if available
660
633
  if CLIENT_SECRET and CLIENT_SECRET != "your_client_secret_here":
661
- data['client_secret'] = CLIENT_SECRET
634
+ data["client_secret"] = CLIENT_SECRET
662
635
 
663
- headers = {
664
- 'Content-Type': 'application/x-www-form-urlencoded'
665
- }
636
+ headers = {"Content-Type": "application/x-www-form-urlencoded"}
666
637
 
667
638
  try:
668
639
  response = requests.post(OAUTH_TOKEN_ENDPOINT, data=data, headers=headers)
@@ -671,15 +642,10 @@ def exchange_authorization_code(authorization_code: str) -> Optional[dict[str, A
671
642
  token_data = response.json()
672
643
 
673
644
  # Calculate expiry time
674
- expires_in = token_data.get('expires_in', 3600)
645
+ expires_in = token_data.get("expires_in", 3600)
675
646
  expiry_time = datetime.now() + timedelta(seconds=expires_in)
676
647
 
677
- new_token = {
678
- 'access_token': token_data['access_token'],
679
- 'token_type': token_data.get('token_type', 'Bearer'),
680
- 'refresh_token': token_data['refresh_token'],
681
- 'expiry': expiry_time.isoformat()
682
- }
648
+ new_token = {"access_token": token_data["access_token"], "token_type": token_data.get("token_type", "Bearer"), "refresh_token": token_data["refresh_token"], "expiry": expiry_time.isoformat()}
683
649
 
684
650
  # Update cached config and save
685
651
  global _cached_config
@@ -793,4 +759,3 @@ if __name__ == "__main__":
793
759
 
794
760
  # Uncomment to test with a file
795
761
  # push_to_onedrive('/home/alex/Downloads/users.xlsx', '/Documents/users.xlsx')
796
-
@@ -1,61 +1,98 @@
1
- from typing import Optional
1
+
2
2
  import platform
3
+ from typing import Optional
3
4
  import subprocess
4
5
  from rich.console import Console
5
6
  from rich.panel import Panel
6
7
  from rich.syntax import Syntax
7
- from machineconfig.utils.utils2 import randstr
8
- from machineconfig.utils.path_reduced import P as PathExtended
9
-
10
8
 
11
- PROGRAM_PATH = (PathExtended.home().joinpath("tmp_results", "shells", "python_return_command") + (".ps1" if platform.system() == "Windows" else ".sh"))
9
+ from machineconfig.utils.utils2 import randstr
10
+ from machineconfig.utils.ve import get_ve_activate_line
11
+ from machineconfig.utils.path_reduced import PathExtended as PathExtended
12
+ from machineconfig.utils.source_of_truth import PROGRAM_PATH
12
13
 
13
14
 
14
- def get_shell_script_executing_python_file(python_file: str, func: Optional[str] = None, ve_name: str="ve", strict_execution: bool=True):
15
- if func is None: exec_line = f"""python {python_file}"""
16
- else: exec_line = f"""python -m fire {python_file} {func}"""
15
+ def get_shell_script_executing_python_file(python_file: str, func: Optional[str], ve_path: str, strict_execution: bool = True):
16
+ if func is None:
17
+ exec_line = f"""python {python_file}"""
18
+ else:
19
+ exec_line = f"""python -m fire {python_file} {func}"""
17
20
  shell_script = f"""
18
- . $HOME/scripts/activate_ve {ve_name}
19
- echo "Executing {exec_line}"
21
+ echo "Executing `{exec_line}`"
22
+ {get_ve_activate_line(ve_path)}
20
23
  {exec_line}
21
24
  deactivate || true
22
25
  """
23
26
 
24
27
  if strict_execution:
25
- if platform.system() == "Windows": shell_script = """$ErrorActionPreference = "Stop" """ + "\n" + shell_script
26
- if platform.system() in ["Linux", "Darwin"]: shell_script = "set -e" + "\n" + shell_script
28
+ if platform.system() == "Windows":
29
+ shell_script = """$ErrorActionPreference = "Stop" """ + "\n" + shell_script
30
+ if platform.system() in ["Linux", "Darwin"]:
31
+ shell_script = "set -e" + "\n" + shell_script
27
32
 
28
- if platform.system() in ["Linux", "Darwin"]: shell_script = "#!/bin/bash" + "\n" + shell_script # vs #!/usr/bin/env bash
33
+ if platform.system() in ["Linux", "Darwin"]:
34
+ shell_script = "#!/bin/bash" + "\n" + shell_script # vs #!/usr/bin/env bash
29
35
  return shell_script
30
36
 
31
37
 
38
+ def get_shell_file_executing_python_script(python_script: str, ve_path: str, verbose: bool = True):
39
+ if verbose:
40
+ python_script = (
41
+ f"""
42
+ code = r'''{python_script}''' """
43
+ + """
44
+ try:
45
+ from machineconfig.utils.utils import print_code
46
+ print_code(code=code, lexer="python", desc="Python Script")
47
+ except ImportError:
48
+ from rich.console import Console
49
+ from rich.panel import Panel
50
+ console = Console()
51
+ console.print(Panel(f'''📜 PYTHON SCRIPT:\n\n{{code}}''', title="Python Script", expand=False))
52
+ """
53
+ + python_script
54
+ )
55
+ python_file = PathExtended.tmp().joinpath("tmp_scripts", "python", randstr() + ".py")
56
+ python_file.parent.mkdir(parents=True, exist_ok=True)
57
+ python_file.write_text(python_script, encoding="utf-8")
58
+ shell_script = get_shell_script_executing_python_file(python_file=str(python_file), func=None, ve_path=ve_path)
59
+ shell_file = write_shell_script_to_file(shell_script)
60
+ return shell_file
61
+
62
+
32
63
  def write_shell_script_to_file(shell_script: str):
33
- if platform.system() in ["Linux", "Darwin"]: suffix = ".sh"
34
- elif platform.system() == "Windows": suffix = ".ps1"
35
- else: raise NotImplementedError(f"Platform {platform.system()} not implemented.")
64
+ if platform.system() in ["Linux", "Darwin"]:
65
+ suffix = ".sh"
66
+ elif platform.system() == "Windows":
67
+ suffix = ".ps1"
68
+ else:
69
+ raise NotImplementedError(f"Platform {platform.system()} not implemented.")
36
70
  shell_file = PathExtended.tmp().joinpath("tmp_scripts", "shell", randstr() + suffix)
37
71
  shell_file.parent.mkdir(parents=True, exist_ok=True)
38
72
  shell_file.write_text(shell_script, encoding="utf-8")
39
73
  return shell_file
40
74
 
75
+
41
76
  # Enhanced print/log/error/exception statements for better clarity and consistency
42
77
  # Improved formatting and language of messages
43
78
  # Ensured consistent use of f-strings with triple quotes where applicable
44
79
 
80
+
45
81
  def write_shell_script_to_default_program_path(program: str, desc: str, preserve_cwd: bool, display: bool, execute: bool):
46
82
  if preserve_cwd:
47
83
  if platform.system() == "Windows":
48
84
  program = "$orig_path = $pwd\n" + program + "\ncd $orig_path"
49
85
  else:
50
86
  program = 'orig_path=$(cd -- "." && pwd)\n' + program + '\ncd "$orig_path" || exit'
51
- if display: print_code(code=program, lexer="shell", desc=desc, subtitle=str(PROGRAM_PATH))
87
+ if display:
88
+ print_code(code=program, lexer="shell", desc=desc, subtitle=str(PROGRAM_PATH))
52
89
  PROGRAM_PATH.parent.mkdir(parents=True, exist_ok=True)
53
90
  PROGRAM_PATH.write_text(program, encoding="utf-8")
54
91
  if execute:
55
92
  result = subprocess.run(f". {PROGRAM_PATH}", shell=True, capture_output=True, text=True)
56
93
  success = result.returncode == 0 and result.stderr == ""
57
94
  if not success:
58
- print(f"❌ 🛠️ EXECUTION | Shell script running failed")
95
+ print("❌ 🛠️ EXECUTION | Shell script running failed")
59
96
  if result.stdout:
60
97
  print(f"STDOUT: {result.stdout}")
61
98
  if result.stderr:
@@ -63,30 +100,14 @@ def write_shell_script_to_default_program_path(program: str, desc: str, preserve
63
100
  print(f"Return code: {result.returncode}")
64
101
  return None
65
102
 
66
- def get_shell_file_executing_python_script(python_script: str, ve_name: str, verbose: bool=True):
67
- if verbose:
68
- python_script = f"""
69
- code = r'''{python_script}''' """ + """
70
- try:
71
- from machineconfig.utils.utils import print_code
72
- print_code(code=code, lexer="python", desc="Python Script")
73
- except ImportError:
74
- from rich.console import Console
75
- from rich.panel import Panel
76
- console = Console()
77
- console.print(Panel(f'''📜 PYTHON SCRIPT:\n\n{{code}}''', title="Python Script", expand=False))
78
- """ + python_script
79
- python_file = PathExtended.tmp().joinpath("tmp_scripts", "python", randstr() + ".py")
80
- python_file.parent.mkdir(parents=True, exist_ok=True)
81
- python_file.write_text(python_script, encoding="utf-8")
82
- shell_script = get_shell_script_executing_python_file(python_file=str(python_file), ve_name=ve_name)
83
- shell_file = write_shell_script_to_file(shell_script)
84
- return shell_file
85
103
 
86
- def print_code(code: str, lexer: str, desc: str, subtitle: str=""):
104
+ def print_code(code: str, lexer: str, desc: str, subtitle: str = ""):
87
105
  if lexer == "shell":
88
- if platform.system() == "Windows": lexer = "powershell"
89
- elif platform.system() in ["Linux", "Darwin"]: lexer = "sh"
90
- else: raise NotImplementedError(f"Platform {platform.system()} not supported for lexer {lexer}")
106
+ if platform.system() == "Windows":
107
+ lexer = "powershell"
108
+ elif platform.system() in ["Linux", "Darwin"]:
109
+ lexer = "sh"
110
+ else:
111
+ raise NotImplementedError(f"Platform {platform.system()} not supported for lexer {lexer}")
91
112
  console = Console()
92
113
  console.print(Panel(Syntax(code=code, lexer=lexer), title=f"📄 {desc}", subtitle=subtitle), style="bold red")