machineconfig 1.97__py3-none-any.whl → 2.1__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 (268) hide show
  1. machineconfig/cluster/cloud_manager.py +22 -29
  2. machineconfig/cluster/data_transfer.py +2 -3
  3. machineconfig/cluster/distribute.py +0 -2
  4. machineconfig/cluster/file_manager.py +4 -5
  5. machineconfig/cluster/job_params.py +1 -4
  6. machineconfig/cluster/loader_runner.py +8 -11
  7. machineconfig/cluster/remote_machine.py +4 -5
  8. machineconfig/cluster/script_execution.py +2 -2
  9. machineconfig/cluster/script_notify_upon_completion.py +0 -1
  10. machineconfig/cluster/sessions_managers/archive/create_zellij_template.py +4 -6
  11. machineconfig/cluster/sessions_managers/archive/session_managers.py +0 -1
  12. machineconfig/cluster/sessions_managers/enhanced_command_runner.py +35 -75
  13. machineconfig/cluster/sessions_managers/wt_local.py +113 -185
  14. machineconfig/cluster/sessions_managers/wt_local_manager.py +127 -197
  15. machineconfig/cluster/sessions_managers/wt_remote.py +60 -67
  16. machineconfig/cluster/sessions_managers/wt_remote_manager.py +110 -149
  17. machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +61 -64
  18. machineconfig/cluster/sessions_managers/wt_utils/process_monitor.py +72 -172
  19. machineconfig/cluster/sessions_managers/wt_utils/remote_executor.py +27 -60
  20. machineconfig/cluster/sessions_managers/wt_utils/session_manager.py +58 -137
  21. machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +46 -74
  22. machineconfig/cluster/sessions_managers/zellij_local.py +91 -147
  23. machineconfig/cluster/sessions_managers/zellij_local_manager.py +165 -190
  24. machineconfig/cluster/sessions_managers/zellij_remote.py +51 -58
  25. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +40 -46
  26. machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +19 -17
  27. machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +30 -31
  28. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +64 -134
  29. machineconfig/cluster/sessions_managers/zellij_utils/remote_executor.py +7 -11
  30. machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +27 -55
  31. machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +14 -13
  32. machineconfig/cluster/templates/cli_click.py +0 -1
  33. machineconfig/cluster/templates/cli_gooey.py +0 -2
  34. machineconfig/cluster/templates/cli_trogon.py +0 -1
  35. machineconfig/cluster/templates/run_cloud.py +0 -1
  36. machineconfig/cluster/templates/run_cluster.py +0 -1
  37. machineconfig/cluster/templates/run_remote.py +0 -1
  38. machineconfig/cluster/templates/utils.py +27 -11
  39. machineconfig/jobs/__pycache__/__init__.cpython-313.pyc +0 -0
  40. machineconfig/jobs/linux/msc/cli_agents.sh +16 -0
  41. machineconfig/jobs/python/check_installations.py +9 -9
  42. machineconfig/jobs/python/create_bootable_media.py +0 -2
  43. machineconfig/jobs/python/python_cargo_build_share.py +2 -2
  44. machineconfig/jobs/python/python_ve_symlink.py +9 -11
  45. machineconfig/jobs/python/tasks.py +0 -1
  46. machineconfig/jobs/python/vscode/api.py +5 -5
  47. machineconfig/jobs/python/vscode/link_ve.py +20 -21
  48. machineconfig/jobs/python/vscode/select_interpreter.py +28 -29
  49. machineconfig/jobs/python/vscode/sync_code.py +14 -18
  50. machineconfig/jobs/python_custom_installers/__pycache__/__init__.cpython-313.pyc +0 -0
  51. machineconfig/jobs/python_custom_installers/archive/ngrok.py +15 -15
  52. machineconfig/jobs/python_custom_installers/dev/aider.py +10 -18
  53. machineconfig/jobs/python_custom_installers/dev/alacritty.py +12 -21
  54. machineconfig/jobs/python_custom_installers/dev/brave.py +13 -22
  55. machineconfig/jobs/python_custom_installers/dev/bypass_paywall.py +13 -20
  56. machineconfig/jobs/python_custom_installers/dev/code.py +17 -24
  57. machineconfig/jobs/python_custom_installers/dev/cursor.py +10 -21
  58. machineconfig/jobs/python_custom_installers/dev/docker_desktop.py +12 -11
  59. machineconfig/jobs/python_custom_installers/dev/espanso.py +19 -23
  60. machineconfig/jobs/python_custom_installers/dev/goes.py +9 -16
  61. machineconfig/jobs/python_custom_installers/dev/lvim.py +13 -21
  62. machineconfig/jobs/python_custom_installers/dev/nerdfont.py +15 -22
  63. machineconfig/jobs/python_custom_installers/dev/redis.py +15 -23
  64. machineconfig/jobs/python_custom_installers/dev/wezterm.py +15 -22
  65. machineconfig/jobs/python_custom_installers/dev/winget.py +32 -50
  66. machineconfig/jobs/python_custom_installers/docker.py +15 -24
  67. machineconfig/jobs/python_custom_installers/gh.py +18 -26
  68. machineconfig/jobs/python_custom_installers/hx.py +33 -17
  69. machineconfig/jobs/python_custom_installers/warp-cli.py +15 -23
  70. machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-313.pyc +0 -0
  71. machineconfig/jobs/python_generic_installers/config.json +412 -389
  72. machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-313.pyc +0 -0
  73. machineconfig/jobs/python_windows_installers/dev/config.json +1 -1
  74. machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +1 -1
  75. machineconfig/jobs/windows/msc/cli_agents.bat +0 -0
  76. machineconfig/jobs/windows/msc/cli_agents.ps1 +0 -0
  77. machineconfig/jobs/windows/start_terminal.ps1 +1 -1
  78. machineconfig/logger.py +50 -0
  79. machineconfig/profile/create.py +50 -36
  80. machineconfig/profile/create_hardlinks.py +33 -26
  81. machineconfig/profile/shell.py +87 -60
  82. machineconfig/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
  83. machineconfig/scripts/cloud/init.sh +2 -2
  84. machineconfig/scripts/linux/checkout_versions +1 -1
  85. machineconfig/scripts/linux/choose_wezterm_theme +1 -1
  86. machineconfig/scripts/linux/cloud_copy +1 -1
  87. machineconfig/scripts/linux/cloud_manager +1 -1
  88. machineconfig/scripts/linux/cloud_mount +1 -1
  89. machineconfig/scripts/linux/cloud_repo_sync +1 -1
  90. machineconfig/scripts/linux/cloud_sync +1 -1
  91. machineconfig/scripts/linux/croshell +1 -1
  92. machineconfig/scripts/linux/devops +3 -5
  93. machineconfig/scripts/linux/fire +2 -1
  94. machineconfig/scripts/linux/fire_agents +3 -3
  95. machineconfig/scripts/linux/ftpx +1 -1
  96. machineconfig/scripts/linux/gh_models +1 -1
  97. machineconfig/scripts/linux/kill_process +1 -1
  98. machineconfig/scripts/linux/mcinit +2 -2
  99. machineconfig/scripts/linux/repos +1 -1
  100. machineconfig/scripts/linux/scheduler +1 -1
  101. machineconfig/scripts/linux/start_slidev +1 -1
  102. machineconfig/scripts/linux/start_terminals +1 -1
  103. machineconfig/scripts/linux/url2md +1 -1
  104. machineconfig/scripts/linux/warp-cli.sh +122 -0
  105. machineconfig/scripts/linux/wifi_conn +1 -1
  106. machineconfig/scripts/python/__pycache__/__init__.cpython-313.pyc +0 -0
  107. machineconfig/scripts/python/__pycache__/croshell.cpython-313.pyc +0 -0
  108. machineconfig/scripts/python/__pycache__/devops.cpython-313.pyc +0 -0
  109. machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-313.pyc +0 -0
  110. machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-313.pyc +0 -0
  111. machineconfig/scripts/python/__pycache__/fire_jobs.cpython-313.pyc +0 -0
  112. machineconfig/scripts/python/ai/__init__.py +0 -0
  113. machineconfig/scripts/python/ai/__pycache__/__init__.cpython-313.pyc +0 -0
  114. machineconfig/scripts/python/ai/__pycache__/generate_files.cpython-313.pyc +0 -0
  115. machineconfig/scripts/python/ai/__pycache__/mcinit.cpython-313.pyc +0 -0
  116. machineconfig/scripts/python/ai/chatmodes/Thinking-Beast-Mode.chatmode.md +337 -0
  117. machineconfig/scripts/python/ai/chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md +644 -0
  118. machineconfig/scripts/python/ai/chatmodes/deepResearch.chatmode.md +81 -0
  119. machineconfig/scripts/python/ai/configs/.gemini/settings.json +81 -0
  120. machineconfig/scripts/python/ai/generate_files.py +84 -0
  121. machineconfig/scripts/python/ai/instructions/python/dev.instructions.md +45 -0
  122. machineconfig/scripts/python/ai/mcinit.py +107 -0
  123. machineconfig/scripts/python/ai/prompts/allLintersAndTypeCheckers.prompt.md +5 -0
  124. machineconfig/scripts/python/ai/prompts/research-report-skeleton.prompt.md +38 -0
  125. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +52 -0
  126. machineconfig/scripts/python/archive/tmate_conn.py +5 -5
  127. machineconfig/scripts/python/archive/tmate_start.py +3 -3
  128. machineconfig/scripts/python/choose_wezterm_theme.py +2 -2
  129. machineconfig/scripts/python/cloud_copy.py +20 -19
  130. machineconfig/scripts/python/cloud_mount.py +10 -8
  131. machineconfig/scripts/python/cloud_repo_sync.py +15 -15
  132. machineconfig/scripts/python/cloud_sync.py +1 -1
  133. machineconfig/scripts/python/croshell.py +18 -16
  134. machineconfig/scripts/python/devops.py +6 -6
  135. machineconfig/scripts/python/devops_add_identity.py +9 -7
  136. machineconfig/scripts/python/devops_add_ssh_key.py +19 -19
  137. machineconfig/scripts/python/devops_backup_retrieve.py +14 -14
  138. machineconfig/scripts/python/devops_devapps_install.py +3 -3
  139. machineconfig/scripts/python/devops_update_repos.py +141 -53
  140. machineconfig/scripts/python/dotfile.py +3 -3
  141. machineconfig/scripts/python/fire_agents.py +202 -41
  142. machineconfig/scripts/python/fire_jobs.py +20 -21
  143. machineconfig/scripts/python/ftpx.py +4 -3
  144. machineconfig/scripts/python/gh_models.py +94 -94
  145. machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-313.pyc +0 -0
  146. machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-313.pyc +0 -0
  147. machineconfig/scripts/python/helpers/cloud_helpers.py +3 -3
  148. machineconfig/scripts/python/helpers/helpers2.py +3 -3
  149. machineconfig/scripts/python/helpers/helpers4.py +8 -7
  150. machineconfig/scripts/python/helpers/helpers5.py +7 -7
  151. machineconfig/scripts/python/helpers/repo_sync_helpers.py +2 -2
  152. machineconfig/scripts/python/mount_nfs.py +4 -3
  153. machineconfig/scripts/python/mount_nw_drive.py +4 -4
  154. machineconfig/scripts/python/mount_ssh.py +4 -3
  155. machineconfig/scripts/python/repos.py +9 -9
  156. machineconfig/scripts/python/scheduler.py +1 -1
  157. machineconfig/scripts/python/start_slidev.py +9 -8
  158. machineconfig/scripts/python/start_terminals.py +1 -1
  159. machineconfig/scripts/python/viewer.py +40 -40
  160. machineconfig/scripts/python/wifi_conn.py +65 -66
  161. machineconfig/scripts/python/wsl_windows_transfer.py +2 -2
  162. machineconfig/scripts/windows/checkout_version.ps1 +1 -3
  163. machineconfig/scripts/windows/choose_wezterm_theme.ps1 +1 -3
  164. machineconfig/scripts/windows/cloud_copy.ps1 +2 -6
  165. machineconfig/scripts/windows/cloud_manager.ps1 +1 -1
  166. machineconfig/scripts/windows/cloud_repo_sync.ps1 +1 -2
  167. machineconfig/scripts/windows/cloud_sync.ps1 +2 -2
  168. machineconfig/scripts/windows/croshell.ps1 +2 -2
  169. machineconfig/scripts/windows/devops.ps1 +1 -4
  170. machineconfig/scripts/windows/dotfile.ps1 +1 -3
  171. machineconfig/scripts/windows/fire.ps1 +1 -1
  172. machineconfig/scripts/windows/ftpx.ps1 +2 -2
  173. machineconfig/scripts/windows/gpt.ps1 +1 -1
  174. machineconfig/scripts/windows/kill_process.ps1 +1 -2
  175. machineconfig/scripts/windows/mcinit.ps1 +2 -2
  176. machineconfig/scripts/windows/mount_nfs.ps1 +1 -1
  177. machineconfig/scripts/windows/mount_ssh.ps1 +1 -1
  178. machineconfig/scripts/windows/pomodoro.ps1 +1 -1
  179. machineconfig/scripts/windows/py2exe.ps1 +1 -3
  180. machineconfig/scripts/windows/repos.ps1 +1 -1
  181. machineconfig/scripts/windows/scheduler.ps1 +1 -1
  182. machineconfig/scripts/windows/snapshot.ps1 +2 -2
  183. machineconfig/scripts/windows/start_slidev.ps1 +1 -1
  184. machineconfig/scripts/windows/start_terminals.ps1 +1 -1
  185. machineconfig/scripts/windows/wifi_conn.ps1 +1 -1
  186. machineconfig/scripts/windows/wsl_windows_transfer.ps1 +1 -3
  187. machineconfig/settings/lf/linux/lfrc +1 -1
  188. machineconfig/settings/linters/.ruff.toml +2 -2
  189. machineconfig/settings/linters/.ruff_cache/.gitignore +2 -0
  190. machineconfig/settings/linters/.ruff_cache/CACHEDIR.TAG +1 -0
  191. machineconfig/settings/lvim/windows/archive/config_additional.lua +1 -1
  192. machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +71 -71
  193. machineconfig/settings/shells/wt/settings.json +8 -8
  194. machineconfig/settings/svim/linux/init.toml +1 -1
  195. machineconfig/settings/svim/windows/init.toml +1 -1
  196. machineconfig/setup_linux/web_shortcuts/croshell.sh +0 -54
  197. machineconfig/setup_linux/web_shortcuts/interactive.sh +6 -6
  198. machineconfig/setup_linux/web_shortcuts/tmp.sh +2 -0
  199. machineconfig/setup_windows/web_shortcuts/all.ps1 +2 -2
  200. machineconfig/setup_windows/web_shortcuts/ascii_art.ps1 +1 -1
  201. machineconfig/setup_windows/web_shortcuts/croshell.ps1 +1 -1
  202. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +5 -5
  203. machineconfig/setup_windows/wt_and_pwsh/install_fonts.ps1 +51 -15
  204. machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +75 -18
  205. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +52 -42
  206. machineconfig/utils/ai/browser_user_wrapper.py +5 -5
  207. machineconfig/utils/ai/generate_file_checklist.py +19 -22
  208. machineconfig/utils/ai/url2md.py +5 -3
  209. machineconfig/utils/cloud/onedrive/setup_oauth.py +5 -4
  210. machineconfig/utils/cloud/onedrive/transaction.py +192 -227
  211. machineconfig/utils/code.py +71 -43
  212. machineconfig/utils/installer.py +77 -85
  213. machineconfig/utils/installer_utils/installer_abc.py +29 -17
  214. machineconfig/utils/installer_utils/installer_class.py +188 -83
  215. machineconfig/utils/io_save.py +3 -15
  216. machineconfig/utils/links.py +22 -11
  217. machineconfig/utils/notifications.py +197 -0
  218. machineconfig/utils/options.py +38 -25
  219. machineconfig/utils/path.py +18 -6
  220. machineconfig/utils/path_reduced.py +637 -316
  221. machineconfig/utils/procs.py +69 -63
  222. machineconfig/utils/scheduling.py +11 -13
  223. machineconfig/utils/ssh.py +351 -0
  224. machineconfig/utils/terminal.py +225 -0
  225. machineconfig/utils/utils.py +13 -12
  226. machineconfig/utils/utils2.py +43 -10
  227. machineconfig/utils/utils5.py +242 -46
  228. machineconfig/utils/ve.py +11 -6
  229. {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/METADATA +15 -9
  230. {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/RECORD +232 -235
  231. machineconfig/cluster/self_ssh.py +0 -57
  232. machineconfig/jobs/__pycache__/__init__.cpython-311.pyc +0 -0
  233. machineconfig/jobs/python/__pycache__/__init__.cpython-311.pyc +0 -0
  234. machineconfig/jobs/python/archive/python_tools.txt +0 -12
  235. machineconfig/jobs/python/vscode/__pycache__/select_interpreter.cpython-311.pyc +0 -0
  236. machineconfig/jobs/python_custom_installers/__pycache__/__init__.cpython-311.pyc +0 -0
  237. machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-311.pyc +0 -0
  238. machineconfig/jobs/python_generic_installers/update.py +0 -3
  239. machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-311.pyc +0 -0
  240. machineconfig/profile/__pycache__/__init__.cpython-311.pyc +0 -0
  241. machineconfig/profile/__pycache__/create.cpython-311.pyc +0 -0
  242. machineconfig/profile/__pycache__/shell.cpython-311.pyc +0 -0
  243. machineconfig/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  244. machineconfig/scripts/linux/activate_ve +0 -87
  245. machineconfig/scripts/python/__pycache__/__init__.cpython-311.pyc +0 -0
  246. machineconfig/scripts/python/__pycache__/cloud_copy.cpython-311.pyc +0 -0
  247. machineconfig/scripts/python/__pycache__/cloud_mount.cpython-311.pyc +0 -0
  248. machineconfig/scripts/python/__pycache__/cloud_sync.cpython-311.pyc +0 -0
  249. machineconfig/scripts/python/__pycache__/croshell.cpython-311.pyc +0 -0
  250. machineconfig/scripts/python/__pycache__/devops.cpython-311.pyc +0 -0
  251. machineconfig/scripts/python/__pycache__/devops_backup_retrieve.cpython-311.pyc +0 -0
  252. machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-311.pyc +0 -0
  253. machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-311.pyc +0 -0
  254. machineconfig/scripts/python/__pycache__/fire_agents.cpython-311.pyc +0 -0
  255. machineconfig/scripts/python/__pycache__/fire_jobs.cpython-311.pyc +0 -0
  256. machineconfig/scripts/python/__pycache__/get_zellij_cmd.cpython-311.pyc +0 -0
  257. machineconfig/scripts/python/__pycache__/repos.cpython-311.pyc +0 -0
  258. machineconfig/scripts/python/ai/__pycache__/init.cpython-311.pyc +0 -0
  259. machineconfig/scripts/python/ai/init.py +0 -56
  260. machineconfig/scripts/python/ai/rules/python/dev.md +0 -31
  261. machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-311.pyc +0 -0
  262. machineconfig/scripts/python/helpers/__pycache__/cloud_helpers.cpython-311.pyc +0 -0
  263. machineconfig/scripts/python/helpers/__pycache__/helpers2.cpython-311.pyc +0 -0
  264. machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-311.pyc +0 -0
  265. machineconfig/scripts/python/helpers/__pycache__/repo_sync_helpers.cpython-311.pyc +0 -0
  266. machineconfig/scripts/windows/activate_ve.ps1 +0 -54
  267. {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/WHEEL +0 -0
  268. {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/top_level.txt +0 -0
@@ -1,55 +1,68 @@
1
-
2
- from machineconfig.utils.path_reduced import P as PathExtended
3
- from crocodile.meta import Terminal
1
+ from machineconfig.utils.path_reduced import PathExtended as PathExtended
4
2
  from machineconfig.utils.installer_utils.installer_abc import find_move_delete_linux, find_move_delete_windows
5
3
  from machineconfig.utils.utils import INSTALL_TMP_DIR, INSTALL_VERSION_ROOT, LIBRARY_ROOT, check_tool_exists
6
4
  from machineconfig.utils.utils2 import pprint, read_json
7
5
 
8
6
  import platform
7
+ import subprocess
9
8
  from typing import Any, Optional
10
9
  from pathlib import Path
11
10
 
12
11
 
13
12
  class Installer:
14
- def __init__(self, repo_url: str, name: str, doc: str,
15
- strip_v: bool, exe_name: str,
16
- filename_template_windows_amd_64: str,
17
- filename_template_linux_amd_64: str,
18
- filename_template_windows_arm_64: Optional[str] = None,
19
- filename_template_linux_arm_64: Optional[str] = None,
20
- filename_template_macos_amd_64: Optional[str] = None,
21
- filename_template_macos_arm_64: Optional[str] = None,
22
- ):
23
- self.repo_url: str=repo_url
24
- self.name: str=name
25
- self.doc: str=doc
26
- self.filename_template_windows_amd_64: str=filename_template_windows_amd_64
27
- self.filename_template_linux_amd_64: str=filename_template_linux_amd_64
28
- self.filename_template_windows_arm_64: Optional[str]=filename_template_windows_arm_64
29
- self.filename_template_linux_arm_64: Optional[str]=filename_template_linux_arm_64
30
- self.filename_template_macos_amd_64: Optional[str]=filename_template_macos_amd_64
31
- self.filename_template_macos_arm_64: Optional[str]=filename_template_macos_arm_64
32
- self.strip_v: bool=strip_v
33
- self.exe_name: str=exe_name
34
- def __repr__(self) -> str: return f"Installer of {self.repo_url}"
13
+ def __init__(
14
+ self,
15
+ repo_url: str,
16
+ name: str,
17
+ doc: str,
18
+ strip_v: bool,
19
+ exe_name: str,
20
+ filename_template_windows_amd_64: str,
21
+ filename_template_linux_amd_64: str,
22
+ filename_template_windows_arm_64: Optional[str] = None,
23
+ filename_template_linux_arm_64: Optional[str] = None,
24
+ filename_template_macos_amd_64: Optional[str] = None,
25
+ filename_template_macos_arm_64: Optional[str] = None,
26
+ ):
27
+ self.repo_url: str = repo_url
28
+ self.name: str = name
29
+ self.doc: str = doc
30
+ self.filename_template_windows_amd_64: str = filename_template_windows_amd_64
31
+ self.filename_template_windows_arm_64: Optional[str] = filename_template_windows_arm_64
32
+ self.filename_template_linux_arm_64: Optional[str] = filename_template_linux_arm_64
33
+ self.filename_template_linux_amd_64: str = filename_template_linux_amd_64
34
+ self.filename_template_macos_amd_64: Optional[str] = filename_template_macos_amd_64
35
+ self.filename_template_macos_arm_64: Optional[str] = filename_template_macos_arm_64
36
+ self.strip_v: bool = strip_v
37
+ self.exe_name: str = exe_name
38
+
39
+ def __repr__(self) -> str:
40
+ return f"Installer of {self.exe_name} {self.name} @ {self.repo_url}"
41
+
35
42
  def get_description(self):
36
43
  # old_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
37
44
  # old_version_cli = os.system(f"{self.exe_name} --version").replace("\n", "")
38
- old_version_cli: bool=check_tool_exists(tool_name=self.exe_name)
45
+ old_version_cli: bool = check_tool_exists(tool_name=self.exe_name)
39
46
  old_version_cli_str = "✅" if old_version_cli else "❌"
40
47
  # name_version = f"{self.exe_name} {old_version_cli_str}"
41
48
  return f"{self.exe_name:<12} {old_version_cli_str} {self.doc}"
42
- def to_dict(self): return self.__dict__
49
+
50
+ def to_dict(self):
51
+ return self.__dict__
52
+
43
53
  @staticmethod
44
54
  def from_dict(d: dict[str, Any], name: str):
45
- try: return Installer(name=name, **d)
55
+ try:
56
+ return Installer(name=name, **d)
46
57
  except Exception as ex:
47
58
  pprint(d, "Installer Creation Error")
48
59
  raise ex
60
+
49
61
  @staticmethod
50
62
  def choose_app_and_install():
51
- print(f"\n{'='*80}\n🔍 SELECT APPLICATION TO INSTALL 🔍\n{'='*80}")
63
+ print(f"\n{'=' * 80}\n🔍 SELECT APPLICATION TO INSTALL 🔍\n{'=' * 80}")
52
64
  from machineconfig.utils.utils import choose_one_option
65
+
53
66
  print("📂 Searching for configuration files...")
54
67
  jobs_dir = Path(LIBRARY_ROOT.joinpath("jobs"))
55
68
  config_paths = [Path(p) for p in jobs_dir.rglob("config.json")]
@@ -62,18 +75,20 @@ class Installer:
62
75
  installer = Installer.from_dict(d=config[app_name], name=app_name)
63
76
  print(f"📦 Selected application: {installer.exe_name}")
64
77
  version = input(f"📝 Enter version to install for {installer.exe_name} [latest]: ") or None
65
- print(f"\n{'='*80}\n🚀 INSTALLING {installer.exe_name.upper()} 🚀\n{'='*80}")
78
+ print(f"\n{'=' * 80}\n🚀 INSTALLING {installer.exe_name.upper()} 🚀\n{'=' * 80}")
66
79
  installer.install(version=version)
67
80
 
68
81
  def install_robust(self, version: Optional[str]):
69
82
  try:
70
- print(f"\n{'='*80}\n🚀 INSTALLING {self.exe_name.upper()} 🚀\n{'='*80}")
71
- old_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
83
+ print(f"\n{'=' * 80}\n🚀 INSTALLING {self.exe_name.upper()} 🚀\n{'=' * 80}")
84
+ result_old = subprocess.run(f"{self.exe_name} --version", shell=True, capture_output=True, text=True)
85
+ old_version_cli = result_old.stdout.strip()
72
86
  print(f"📊 Current version: {old_version_cli or 'Not installed'}")
73
87
 
74
88
  self.install(version=version)
75
89
 
76
- new_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
90
+ result_new = subprocess.run(f"{self.exe_name} --version", shell=True, capture_output=True, text=True)
91
+ new_version_cli = result_new.stdout.strip()
77
92
  print(f"📊 New version: {new_version_cli}")
78
93
 
79
94
  if old_version_cli == new_version_cli:
@@ -88,10 +103,11 @@ class Installer:
88
103
  return f"""echo "📦️ ❌ Failed to install `{self.name}` with error: {ex}" """
89
104
 
90
105
  def install(self, version: Optional[str]):
91
- print(f"\n{'='*80}\n🔧 INSTALLATION PROCESS: {self.exe_name} 🔧\n{'='*80}")
106
+ print(f"\n{'=' * 80}\n🔧 INSTALLATION PROCESS: {self.exe_name} 🔧\n{'=' * 80}")
92
107
  if self.repo_url == "CUSTOM":
93
108
  print(f"🧩 Using custom installer for {self.exe_name}")
94
109
  import machineconfig.jobs.python_custom_installers as python_custom_installers
110
+
95
111
  installer_path = Path(python_custom_installers.__file__).parent.joinpath(self.exe_name + ".py")
96
112
  if not installer_path.exists():
97
113
  installer_path = Path(python_custom_installers.__file__).parent.joinpath("dev", self.exe_name + ".py")
@@ -100,15 +116,25 @@ class Installer:
100
116
  print(f"🔍 Found installer at: {installer_path}")
101
117
 
102
118
  import runpy
119
+
103
120
  print(f"⚙️ Executing function 'main' from '{installer_path}'...")
104
- program: str = runpy.run_path(str(installer_path), run_name=None)['main'](version=version)
121
+ program: str = runpy.run_path(str(installer_path), run_name=None)["main"](version=version)
105
122
  # print(program)
106
123
  print("🚀 Running installation script...")
107
- Terminal(stdin=None, stdout=None, stderr=None).run_script(script=program, shell="default").print(desc="Running custom installer", capture=True)
108
- # import subprocess
109
- # subprocess.run(program, shell=True, check=True)
124
+ if platform.system() == "Linux":
125
+ script = "#!/bin/bash" + "\n" + program
126
+ else:
127
+ script = program
128
+ script_file = PathExtended.tmpfile(name="tmp_shell_script", suffix=".ps1" if platform.system() == "Windows" else ".sh", folder="tmp_scripts").write_text(script, newline=None if platform.system() == "Windows" else "\n")
129
+ if platform.system() == "Windows":
130
+ start_cmd = "powershell"
131
+ full_command = f"{start_cmd} {script_file}"
132
+ else:
133
+ start_cmd = "bash"
134
+ full_command = f"{start_cmd} {script_file}"
135
+ subprocess.run(full_command, stdin=None, stdout=None, stderr=None, shell=True, text=True)
110
136
  version_to_be_installed = str(version)
111
- print(f"✅ Custom installation completed\n{'='*80}")
137
+ print(f"✅ Custom installation completed\n{'=' * 80}")
112
138
 
113
139
  elif "npm " in self.repo_url or "pip " in self.repo_url or "winget " in self.repo_url:
114
140
  package_manager = self.repo_url.split(" ", maxsplit=1)[0]
@@ -116,8 +142,16 @@ class Installer:
116
142
  desc = package_manager + " installation"
117
143
  version_to_be_installed = package_manager + "Latest"
118
144
  print(f"🚀 Running: {self.repo_url}")
119
- Terminal().run(self.repo_url, shell="default").capture().print_if_unsuccessful(desc=desc, strict_err=True, strict_returncode=True)
120
- print(f"✅ Package manager installation completed\n{'='*80}")
145
+ result = subprocess.run(self.repo_url, shell=True, capture_output=True, text=True)
146
+ success = result.returncode == 0 and result.stderr == ""
147
+ if not success:
148
+ print(f"❌ {desc} failed")
149
+ if result.stdout:
150
+ print(f"STDOUT: {result.stdout}")
151
+ if result.stderr:
152
+ print(f"STDERR: {result.stderr}")
153
+ print(f"Return code: {result.returncode}")
154
+ print(f"✅ Package manager installation completed\n{'=' * 80}")
121
155
 
122
156
  else:
123
157
  print("📥 Downloading from repository...")
@@ -125,10 +159,19 @@ class Installer:
125
159
  if str(downloaded).endswith(".deb"):
126
160
  print(f"📦 Installing .deb package: {downloaded}")
127
161
  assert platform.system() == "Linux"
128
- Terminal().run(f"sudo nala install -y {downloaded}").capture().print_if_unsuccessful(desc="Installing .deb", strict_err=True, strict_returncode=True)
162
+ result = subprocess.run(f"sudo nala install -y {downloaded}", shell=True, capture_output=True, text=True)
163
+ success = result.returncode == 0 and result.stderr == ""
164
+ if not success:
165
+ desc = "Installing .deb"
166
+ print(f"❌ {desc} failed")
167
+ if result.stdout:
168
+ print(f"STDOUT: {result.stdout}")
169
+ if result.stderr:
170
+ print(f"STDERR: {result.stderr}")
171
+ print(f"Return code: {result.returncode}")
129
172
  print("🗑️ Cleaning up .deb package...")
130
173
  downloaded.delete(sure=True)
131
- print(f"✅ DEB package installation completed\n{'='*80}")
174
+ print(f"✅ DEB package installation completed\n{'=' * 80}")
132
175
  else:
133
176
  if platform.system() == "Windows":
134
177
  print("🪟 Installing on Windows...")
@@ -146,6 +189,7 @@ class Installer:
146
189
  if exe.name.replace(".exe", "") != self.exe_name.replace(".exe", ""):
147
190
  from rich import print as pprint
148
191
  from rich.panel import Panel
192
+
149
193
  print("⚠️ Warning: Executable name mismatch")
150
194
  pprint(Panel(f"Expected exe name: [red]{self.exe_name}[/red] \nAttained name: [red]{exe.name.replace('.exe', '')}[/red]", title="exe name mismatch", subtitle=self.repo_url))
151
195
  new_exe_name = self.exe_name + ".exe" if platform.system() == "Windows" else self.exe_name
@@ -154,31 +198,31 @@ class Installer:
154
198
 
155
199
  print(f"💾 Saving version information to: {INSTALL_VERSION_ROOT.joinpath(self.exe_name)}")
156
200
  INSTALL_VERSION_ROOT.joinpath(self.exe_name).parent.mkdir(parents=True, exist_ok=True)
157
- INSTALL_VERSION_ROOT.joinpath(self.exe_name).write_text(version_to_be_installed)
158
- print(f"✅ Installation completed successfully!\n{'='*80}")
201
+ INSTALL_VERSION_ROOT.joinpath(self.exe_name).write_text(version_to_be_installed, encoding="utf-8")
202
+ print(f"✅ Installation completed successfully!\n{'=' * 80}")
159
203
 
160
204
  def download(self, version: Optional[str]):
161
- print(f"\n{'='*80}\n📥 DOWNLOADING: {self.exe_name} 📥\n{'='*80}")
205
+ print(f"\n{'=' * 80}\n📥 DOWNLOADING: {self.exe_name} 📥\n{'=' * 80}")
206
+ download_link: Optional[Path] = None
207
+ version_to_be_installed: Optional[str] = None
162
208
  if "github" not in self.repo_url or ".zip" in self.repo_url or ".tar.gz" in self.repo_url:
163
209
  download_link = Path(self.repo_url)
164
210
  version_to_be_installed = "predefined_url"
165
211
  print(f"🔗 Using direct download URL: {download_link}")
166
212
  print(f"📦 Version to be installed: {version_to_be_installed}")
167
-
168
- elif "http" in self.filename_template_linux_amd_64 or "http" in self.filename_template_windows_amd_64:
169
- if platform.system() == "Windows":
170
- download_link = Path(self.filename_template_windows_amd_64)
171
- print(f"🪟 Using Windows-specific download URL: {download_link}")
172
- elif platform.system() in ["Linux", "Darwin"]:
173
- download_link = Path(self.filename_template_linux_amd_64)
174
- system_name = "Linux" if platform.system() == "Linux" else "macOS"
175
- print(f"🐧 Using {system_name}-specific download URL: {download_link}")
213
+ elif self._any_direct_http_template():
214
+ template, arch = self._select_template()
215
+ if not template.startswith("http"):
216
+ # Fall back to github-style handling below
217
+ pass
176
218
  else:
177
- error_msg = f"❌ ERROR: System {platform.system()} not supported"
178
- print(error_msg)
179
- raise NotImplementedError(error_msg)
180
-
181
- version_to_be_installed = "predefined_url"
219
+ download_link = Path(template)
220
+ version_to_be_installed = "predefined_url"
221
+ system_name = self._system_name()
222
+ print(f"🧭 Detected system={system_name} arch={arch}")
223
+ print(f"🔗 Using architecture-specific direct URL: {download_link}")
224
+ print(f"📦 Version to be installed: {version_to_be_installed}")
225
+ # continue to unified download logic below
182
226
 
183
227
  else:
184
228
  print("🌐 Retrieving release information from GitHub...")
@@ -189,36 +233,97 @@ class Installer:
189
233
  version_to_be_installed_stripped = version_to_be_installed.replace("v", "") if self.strip_v else version_to_be_installed
190
234
  version_to_be_installed_stripped = version_to_be_installed_stripped.replace("ipinfo-", "")
191
235
 
192
- if platform.system() == "Windows":
193
- file_name = self.filename_template_windows_amd_64.format(version_to_be_installed_stripped)
194
- print(f"🪟 Windows file name: {file_name}")
195
- elif platform.system() in ["Linux", "Darwin"]:
196
- file_name = self.filename_template_linux_amd_64.format(version_to_be_installed_stripped)
197
- system_name = "Linux" if platform.system() == "Linux" else "macOS"
198
- print(f"🐧 {system_name} file name: {file_name}")
199
- else:
200
- error_msg = f"❌ ERROR: System {platform.system()} not supported"
201
- print(error_msg)
202
- raise NotImplementedError(error_msg)
236
+ template, arch = self._select_template()
237
+ system_name = self._system_name()
238
+ file_name = template.format(version_to_be_installed_stripped)
239
+ print(f"🧭 Detected system={system_name} arch={arch}")
240
+ print(f"📄 Using template: {template}")
241
+ print(f"🗂️ Resolved file name: {file_name}")
203
242
 
204
243
  print(f"📄 File name: {file_name}")
205
244
  download_link = release_url.joinpath(file_name)
206
245
 
246
+ assert download_link is not None, "download_link must be set"
247
+ assert version_to_be_installed is not None, "version_to_be_installed must be set"
207
248
  print(f"📥 Downloading {self.name} from: {download_link}")
208
249
  downloaded = PathExtended(download_link).download(folder=INSTALL_TMP_DIR).decompress()
209
- print(f"✅ Download and extraction completed to: {downloaded}\n{'='*80}")
250
+ print(f"✅ Download and extraction completed to: {downloaded}\n{'=' * 80}")
210
251
  return downloaded, version_to_be_installed
211
252
 
253
+ # --------------------------- Arch / template helpers ---------------------------
254
+ def _normalized_arch(self) -> str:
255
+ arch_raw = platform.machine().lower()
256
+ if arch_raw in ("x86_64", "amd64"):
257
+ return "amd64"
258
+ if arch_raw in ("aarch64", "arm64", "armv8", "armv8l"):
259
+ return "arm64"
260
+ return arch_raw
261
+
262
+ def _system_name(self) -> str:
263
+ sys_ = platform.system()
264
+ if sys_ == "Darwin":
265
+ return "macOS"
266
+ return sys_
267
+
268
+ def _any_direct_http_template(self) -> bool:
269
+ templates: list[Optional[str]] = [
270
+ self.filename_template_windows_amd_64,
271
+ self.filename_template_windows_arm_64,
272
+ self.filename_template_linux_amd_64,
273
+ self.filename_template_linux_arm_64,
274
+ self.filename_template_macos_amd_64,
275
+ self.filename_template_macos_arm_64,
276
+ ]
277
+ return any(t for t in templates if t is not None and t.startswith("http"))
278
+
279
+ def _select_template(self) -> tuple[str, str]:
280
+ sys_name = platform.system()
281
+ arch = self._normalized_arch()
282
+ # mapping logic
283
+ candidates: list[str] = []
284
+ template: Optional[str] = None
285
+ if sys_name == "Windows":
286
+ if arch == "arm64" and self.filename_template_windows_arm_64:
287
+ template = self.filename_template_windows_arm_64
288
+ else:
289
+ template = self.filename_template_windows_amd_64
290
+ candidates = ["filename_template_windows_arm_64", "filename_template_windows_amd_64"]
291
+ elif sys_name == "Linux":
292
+ if arch == "arm64" and self.filename_template_linux_arm_64:
293
+ template = self.filename_template_linux_arm_64
294
+ else:
295
+ template = self.filename_template_linux_amd_64
296
+ candidates = ["filename_template_linux_arm_64", "filename_template_linux_amd_64"]
297
+ elif sys_name == "Darwin":
298
+ if arch == "arm64" and self.filename_template_macos_arm_64:
299
+ template = self.filename_template_macos_arm_64
300
+ elif arch == "amd64" and self.filename_template_macos_amd_64:
301
+ template = self.filename_template_macos_amd_64
302
+ else:
303
+ # fallback between available mac templates
304
+ template = self.filename_template_macos_arm_64 or self.filename_template_macos_amd_64
305
+ candidates = ["filename_template_macos_arm_64", "filename_template_macos_amd_64"]
306
+ else:
307
+ raise NotImplementedError(f"System {sys_name} not supported")
308
+
309
+ if template is None:
310
+ raise ValueError(f"No filename template available for system={sys_name} arch={arch}. Checked {candidates}")
311
+
312
+ return template, arch
313
+
212
314
  @staticmethod
213
315
  def get_github_release(repo_url: str, version: Optional[str] = None):
214
- print(f"\n{'='*80}\n🔍 GITHUB RELEASE DETECTION 🔍\n{'='*80}")
316
+ print(f"\n{'=' * 80}\n🔍 GITHUB RELEASE DETECTION 🔍\n{'=' * 80}")
215
317
  print(f"🌐 Inspecting releases at: {repo_url}")
216
318
  # with console.status("Installing..."): # makes troubles on linux when prompt asks for password to move file to /usr/bin
217
319
  if version is None:
218
320
  # see this: https://api.github.com/repos/cointop-sh/cointop/releases/latest
219
321
  print("🔍 Finding latest version...")
220
322
  import requests # https://docs.github.com/en/repositories/releasing-projects-on-github/linking-to-releases
221
- _latest_version = requests.get(str(repo_url) + "/releases/latest", timeout=10).url.split("/")[-1] # this is to resolve the redirection that occures: https://stackoverflow.com/questions/36070821/how-to-get-redirect-url-using-python-requests
323
+
324
+ _latest_version = requests.get(str(repo_url) + "/releases/latest", timeout=10).url.split("/")[
325
+ -1
326
+ ] # this is to resolve the redirection that occures: https://stackoverflow.com/questions/36070821/how-to-get-redirect-url-using-python-requests
222
327
  version_to_be_installed = _latest_version
223
328
  print(f"✅ Latest version detected: {version_to_be_installed}")
224
329
  # print(version_to_be_installed)
@@ -227,12 +332,12 @@ class Installer:
227
332
  print(f"📝 Using specified version: {version_to_be_installed}")
228
333
 
229
334
  release_url = Path(repo_url + "/releases/download/" + version_to_be_installed)
230
- print(f"🔗 Release download URL: {release_url}\n{'='*80}")
335
+ print(f"🔗 Release download URL: {release_url}\n{'=' * 80}")
231
336
  return release_url, version_to_be_installed
232
337
 
233
338
  @staticmethod
234
339
  def check_if_installed_already(exe_name: str, version: str, use_cache: bool):
235
- print(f"\n{'='*80}\n🔍 CHECKING INSTALLATION STATUS: {exe_name} 🔍\n{'='*80}")
340
+ print(f"\n{'=' * 80}\n🔍 CHECKING INSTALLATION STATUS: {exe_name} 🔍\n{'=' * 80}")
236
341
  version_to_be_installed = version
237
342
  INSTALL_VERSION_ROOT.joinpath(exe_name).parent.mkdir(parents=True, exist_ok=True)
238
343
  tmp_path = INSTALL_VERSION_ROOT.joinpath(exe_name)
@@ -240,19 +345,19 @@ class Installer:
240
345
  if use_cache:
241
346
  print("🗂️ Using cached version information...")
242
347
  if tmp_path.exists():
243
- existing_version = tmp_path.read_text().rstrip()
348
+ existing_version = tmp_path.read_text(encoding="utf-8").rstrip()
244
349
  print(f"📄 Found cached version: {existing_version}")
245
350
  else:
246
351
  existing_version = None
247
352
  print("ℹ️ No cached version information found")
248
353
  else:
249
354
  print("🔍 Checking installed version directly...")
250
- resp = Terminal().run(exe_name, "--version", check=False).capture()
251
- if resp.op == '':
355
+ result = subprocess.run([exe_name, "--version"], check=False, capture_output=True, text=True)
356
+ if result.stdout.strip() == "":
252
357
  existing_version = None
253
358
  print("ℹ️ Could not detect installed version")
254
359
  else:
255
- existing_version = resp.op.strip()
360
+ existing_version = result.stdout.strip()
256
361
  print(f"📄 Detected installed version: {existing_version}")
257
362
 
258
363
  if existing_version is not None:
@@ -262,11 +367,11 @@ class Installer:
262
367
  return ("✅ Uptodate", version.strip(), version_to_be_installed.strip())
263
368
  else:
264
369
  print(f"🔄 {exe_name} needs update: {existing_version.rstrip()} → {version_to_be_installed}")
265
- tmp_path.write_text(version_to_be_installed)
370
+ tmp_path.write_text(version_to_be_installed, encoding="utf-8")
266
371
  return ("❌ Outdated", existing_version.strip(), version_to_be_installed.strip())
267
372
  else:
268
373
  print(f"📦 {exe_name} is not installed. Will install version: {version_to_be_installed}")
269
- tmp_path.write_text(version_to_be_installed)
374
+ tmp_path.write_text(version_to_be_installed, encoding="utf-8")
270
375
 
271
- print(f"{'='*80}")
272
- return ("⚠️ NotInstalled", "None", version_to_be_installed.strip())
376
+ print(f"{'=' * 80}")
377
+ return ("⚠️ NotInstalled", "None", version_to_be_installed.strip())
@@ -5,16 +5,8 @@ from pathlib import Path
5
5
  import json
6
6
  import pickle
7
7
  import configparser
8
-
9
- try:
10
- import toml # type: ignore
11
- except Exception: # pragma: no cover
12
- toml = None # type: ignore
13
-
14
- try:
15
- import yaml # type: ignore
16
- except Exception: # pragma: no cover
17
- yaml = None # type: ignore
8
+ import toml
9
+ import yaml
18
10
 
19
11
 
20
12
  PathLike = Union[str, Path]
@@ -46,8 +38,6 @@ def save_json(obj: Any, path: PathLike, indent: Optional[int] = None, verbose: b
46
38
 
47
39
 
48
40
  def save_toml(obj: Mapping[str, Any], path: PathLike, verbose: bool = False) -> Path:
49
- if toml is None:
50
- raise RuntimeError("toml package is required to write TOML files")
51
41
  path_obj = _ensure_parent(path)
52
42
  with open(path_obj, "w", encoding="utf-8") as fh:
53
43
  toml.dump(obj, fh)
@@ -57,8 +47,6 @@ def save_toml(obj: Mapping[str, Any], path: PathLike, verbose: bool = False) ->
57
47
 
58
48
 
59
49
  def save_yaml(obj: Any, path: PathLike, verbose: bool = False) -> Path:
60
- if yaml is None:
61
- raise RuntimeError("PyYAML is required to write YAML files")
62
50
  path_obj = _ensure_parent(path)
63
51
  with open(path_obj, "w", encoding="utf-8") as fh:
64
52
  yaml.safe_dump(obj, fh, sort_keys=False)
@@ -80,7 +68,7 @@ def save_ini(path: PathLike, obj: Mapping[str, Mapping[str, Any]], verbose: bool
80
68
 
81
69
 
82
70
  class Save:
83
- """Drop-in replacement for crocodile's Save helper.
71
+ """
84
72
 
85
73
  Provides static methods for common serialization formats while ensuring
86
74
  parent directories exist and returning a `P` path object.
@@ -1,4 +1,4 @@
1
- from machineconfig.utils.path_reduced import P as PathExtended, PLike
1
+ from machineconfig.utils.path_reduced import PathExtended as PathExtended, PLike
2
2
  from machineconfig.utils.utils2 import randstr
3
3
  from rich.console import Console
4
4
  from rich.panel import Panel
@@ -19,6 +19,7 @@ def build_links(target_paths: list[tuple[PLike, str]], repo_root: PLike):
19
19
  target_dirs_filtered.append((a_dir_obj, a_name))
20
20
 
21
21
  import git
22
+
22
23
  repo = git.Repo(repo_root, search_parent_directories=True)
23
24
  root_maybe = repo.working_tree_dir
24
25
  assert root_maybe is not None
@@ -31,7 +32,8 @@ def build_links(target_paths: list[tuple[PLike, str]], repo_root: PLike):
31
32
  links_path = repo_root_obj.joinpath("links", a_name)
32
33
  links_path.symlink_to(target=a_target_path)
33
34
 
34
- def symlink_func(this: PathExtended, to_this: PathExtended, prioritize_to_this: bool=True):
35
+
36
+ def symlink_func(this: PathExtended, to_this: PathExtended, prioritize_to_this: bool = True):
35
37
  """helper function. creates a symlink from `this` to `to_this`.
36
38
  What can go wrong?
37
39
  depending on this and to_this existence, one will be prioretized depending on overwrite value.
@@ -39,15 +41,19 @@ def symlink_func(this: PathExtended, to_this: PathExtended, prioritize_to_this:
39
41
  False means to_this will potentially be overwittten."""
40
42
  this = PathExtended(this).expanduser().absolute()
41
43
  to_this = PathExtended(to_this).expanduser().absolute()
42
- if this.is_symlink(): this.delete(sure=True) # delete if it exists as symblic link, not a concrete path.
44
+ if this.is_symlink():
45
+ this.delete(sure=True) # delete if it exists as symblic link, not a concrete path.
43
46
  if this.exists(): # this is a problem. It will be resolved via `overwrite`
44
47
  if prioritize_to_this is True: # it *can* be deleted, but let's look at target first.
45
48
  if to_this.exists(): # this exists, to_this as well. to_this is prioritized.
46
49
  this.append(f".orig_{randstr()}", inplace=True) # rename is better than deletion
47
- else: this.move(path=to_this) # this exists, to_this doesn't. to_this is prioritized.
50
+ else:
51
+ this.move(path=to_this) # this exists, to_this doesn't. to_this is prioritized.
48
52
  elif prioritize_to_this is False: # don't sacrefice this, sacrefice to_this.
49
- if to_this.exists(): this.move(path=to_this, overwrite=True) # this exists, to_this as well, this is prioritized. # now we are readly to make the link
50
- else: this.move(path=to_this) # this exists, to_this doesn't, this is prioritized.
53
+ if to_this.exists():
54
+ this.move(path=to_this, overwrite=True) # this exists, to_this as well, this is prioritized. # now we are readly to make the link
55
+ else:
56
+ this.move(path=to_this) # this exists, to_this doesn't, this is prioritized.
51
57
  else: # this doesn't exist.
52
58
  if not to_this.exists():
53
59
  to_this.parent.mkdir(parents=True, exist_ok=True)
@@ -58,18 +64,23 @@ def symlink_func(this: PathExtended, to_this: PathExtended, prioritize_to_this:
58
64
  except Exception as ex:
59
65
  console.print(Panel(f"❌ ERROR | Failed at linking {this} ➡️ {to_this}. Reason: {ex}", title="Error", expand=False))
60
66
 
61
- def symlink_copy(this: PathExtended, to_this: PathExtended, prioritize_to_this: bool=True):
67
+
68
+ def symlink_copy(this: PathExtended, to_this: PathExtended, prioritize_to_this: bool = True):
62
69
  this = PathExtended(this).expanduser().absolute()
63
70
  to_this = PathExtended(to_this).expanduser().absolute()
64
- if this.is_symlink(): this.delete(sure=True) # delete if it exists as symblic link, not a concrete path.
71
+ if this.is_symlink():
72
+ this.delete(sure=True) # delete if it exists as symblic link, not a concrete path.
65
73
  if this.exists(): # this is a problem. It will be resolved via `overwrite`
66
74
  if prioritize_to_this is True: # it *can* be deleted, but let's look at target first.
67
75
  if to_this.exists(): # this exists, to_this as well. to_this is prioritized.
68
76
  this.append(f".orig_{randstr()}", inplace=True) # rename is better than deletion
69
- else: this.move(path=to_this) # this exists, to_this doesn't. to_this is prioritized.
77
+ else:
78
+ this.move(path=to_this) # this exists, to_this doesn't. to_this is prioritized.
70
79
  elif prioritize_to_this is False: # don't sacrefice this, sacrefice to_this.
71
- if to_this.exists(): this.move(path=to_this, overwrite=True) # this exists, to_this as well, this is prioritized. # now we are readly to make the link
72
- else: this.move(path=to_this) # this exists, to_this doesn't, this is prioritized.
80
+ if to_this.exists():
81
+ this.move(path=to_this, overwrite=True) # this exists, to_this as well, this is prioritized. # now we are readly to make the link
82
+ else:
83
+ this.move(path=to_this) # this exists, to_this doesn't, this is prioritized.
73
84
  else: # this doesn't exist.
74
85
  if not to_this.exists():
75
86
  to_this.parent.mkdir(parents=True, exist_ok=True)