machineconfig 5.15__py3-none-any.whl → 7.98__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.
Files changed (472) hide show
  1. machineconfig/__init__.py +0 -28
  2. machineconfig/cluster/remote/cloud_manager.py +1 -1
  3. machineconfig/cluster/remote/distribute.py +0 -1
  4. machineconfig/cluster/remote/file_manager.py +0 -2
  5. machineconfig/cluster/remote/script_execution.py +0 -1
  6. machineconfig/cluster/sessions_managers/{utils → helpers}/enhanced_command_runner.py +4 -6
  7. machineconfig/cluster/sessions_managers/utils/load_balancer.py +1 -1
  8. machineconfig/cluster/sessions_managers/utils/maker.py +69 -0
  9. machineconfig/cluster/sessions_managers/wt_local.py +114 -289
  10. machineconfig/cluster/sessions_managers/wt_local_manager.py +70 -210
  11. machineconfig/cluster/sessions_managers/wt_remote.py +51 -43
  12. machineconfig/cluster/sessions_managers/wt_remote_manager.py +52 -198
  13. machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +6 -19
  14. machineconfig/cluster/sessions_managers/wt_utils/manager_persistence.py +52 -0
  15. machineconfig/cluster/sessions_managers/wt_utils/monitoring_helpers.py +50 -0
  16. machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +4 -2
  17. machineconfig/cluster/sessions_managers/wt_utils/status_reporting.py +76 -0
  18. machineconfig/cluster/sessions_managers/wt_utils/wt_helpers.py +199 -0
  19. machineconfig/cluster/sessions_managers/zellij_local.py +81 -375
  20. machineconfig/cluster/sessions_managers/zellij_local_manager.py +25 -170
  21. machineconfig/cluster/sessions_managers/zellij_remote.py +40 -41
  22. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +16 -12
  23. machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +4 -8
  24. machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +5 -20
  25. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +3 -9
  26. machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +3 -1
  27. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_helper.py +298 -0
  28. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_helper_restart.py +77 -0
  29. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_helper_with_panes.py +228 -0
  30. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_manager_helper.py +165 -0
  31. machineconfig/jobs/{python → installer}/check_installations.py +2 -3
  32. machineconfig/jobs/installer/custom/boxes.py +61 -0
  33. machineconfig/jobs/installer/custom/hx.py +76 -19
  34. machineconfig/jobs/installer/custom/yazi.py +119 -0
  35. machineconfig/jobs/installer/custom_dev/alacritty.py +4 -4
  36. machineconfig/jobs/installer/custom_dev/brave.py +5 -9
  37. machineconfig/jobs/installer/custom_dev/cloudflare_warp_cli.py +23 -0
  38. machineconfig/jobs/installer/custom_dev/code.py +4 -1
  39. machineconfig/jobs/installer/custom_dev/dubdb_adbc.py +30 -0
  40. machineconfig/jobs/installer/custom_dev/nerdfont.py +1 -1
  41. machineconfig/jobs/installer/custom_dev/nerfont_windows_helper.py +33 -28
  42. machineconfig/jobs/installer/custom_dev/sysabc.py +139 -0
  43. machineconfig/jobs/installer/custom_dev/wezterm.py +2 -19
  44. machineconfig/jobs/installer/custom_dev/winget.py +10 -14
  45. machineconfig/jobs/installer/installer_data.json +1487 -229
  46. machineconfig/jobs/installer/linux_scripts/brave.sh +4 -14
  47. machineconfig/jobs/installer/linux_scripts/{warp-cli.sh → cloudflare_warp_cli.sh} +5 -17
  48. machineconfig/jobs/installer/linux_scripts/docker.sh +5 -17
  49. machineconfig/jobs/installer/linux_scripts/docker_start.sh +6 -14
  50. machineconfig/jobs/installer/linux_scripts/edge.sh +3 -11
  51. machineconfig/jobs/{linux/msc → installer/linux_scripts}/lid.sh +2 -8
  52. machineconfig/jobs/installer/linux_scripts/nerdfont.sh +5 -17
  53. machineconfig/jobs/{linux/msc → installer/linux_scripts}/network.sh +2 -8
  54. machineconfig/jobs/installer/linux_scripts/q.sh +10 -6
  55. machineconfig/jobs/installer/linux_scripts/redis.sh +6 -17
  56. machineconfig/jobs/installer/linux_scripts/vscode.sh +5 -17
  57. machineconfig/jobs/installer/linux_scripts/wezterm.sh +4 -12
  58. machineconfig/jobs/installer/package_groups.py +106 -177
  59. machineconfig/jobs/installer/powershell_scripts/install_fonts.ps1 +129 -34
  60. machineconfig/logger.py +0 -1
  61. machineconfig/profile/backup.toml +49 -0
  62. machineconfig/profile/bash_shell_profiles.md +11 -0
  63. machineconfig/profile/create_helper.py +62 -0
  64. machineconfig/profile/create_links.py +288 -0
  65. machineconfig/profile/create_links_export.py +100 -0
  66. machineconfig/profile/create_shell_profile.py +147 -0
  67. machineconfig/profile/mapper.toml +263 -0
  68. machineconfig/scripts/__init__.py +0 -4
  69. machineconfig/scripts/linux/{share_cloud.sh → other/share_cloud.sh} +14 -25
  70. machineconfig/scripts/linux/wrap_mcfg +46 -0
  71. machineconfig/scripts/nu/wrap_mcfg.nu +69 -0
  72. machineconfig/scripts/python/agents.py +123 -117
  73. machineconfig/scripts/python/ai/initai.py +3 -28
  74. machineconfig/scripts/python/ai/scripts/command_runner.ps1 +33 -0
  75. machineconfig/scripts/python/ai/scripts/command_runner.sh +9 -0
  76. machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +17 -18
  77. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +17 -18
  78. machineconfig/scripts/python/ai/solutions/_shared.py +9 -1
  79. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Thinking-Beast-Mode.chatmode.md → agents/Thinking-Beast-Mode.agent.md} +0 -1
  80. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md → agents/Ultimate-Transparent-Thinking-Beast-Mode.agent.md} +0 -1
  81. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/deepResearch.chatmode.md → agents/deepResearch.agent.md} +2 -2
  82. machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +5 -5
  83. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +5 -1
  84. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/watch_exec.prompt.md +20 -0
  85. machineconfig/scripts/python/ai/solutions/copilot/prompts/pyright_fix.md +16 -0
  86. machineconfig/scripts/python/ai/solutions/generic.py +28 -5
  87. machineconfig/scripts/python/ai/utils/generate_files.py +348 -0
  88. machineconfig/scripts/python/ai/utils/vscode_tasks.py +37 -0
  89. machineconfig/scripts/python/cloud.py +29 -0
  90. machineconfig/scripts/python/croshell.py +137 -113
  91. machineconfig/scripts/python/devops.py +61 -101
  92. machineconfig/scripts/python/devops_navigator.py +6 -0
  93. machineconfig/scripts/python/env_manager/__init__.py +1 -0
  94. machineconfig/scripts/python/env_manager/env_manager_tui.py +204 -0
  95. machineconfig/scripts/python/env_manager/path_manager_backend.py +47 -0
  96. machineconfig/scripts/python/env_manager/path_manager_tui.py +228 -0
  97. machineconfig/scripts/python/fire_jobs.py +110 -150
  98. machineconfig/scripts/python/ftpx.py +51 -24
  99. machineconfig/scripts/python/helpers/ast_search.py +74 -0
  100. machineconfig/scripts/python/helpers/qr_code.py +166 -0
  101. machineconfig/scripts/python/helpers/repo_rag.py +325 -0
  102. machineconfig/scripts/python/helpers/run_py_script.py +79 -0
  103. machineconfig/scripts/python/helpers/symantic_search.py +25 -0
  104. machineconfig/scripts/python/helpers/tmp_py_scripts/a.py +26 -0
  105. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.json +14 -0
  106. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.py +39 -0
  107. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_cursor_agents.py +22 -0
  108. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_gemini.py +55 -0
  109. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_qwen.py +30 -0
  110. machineconfig/scripts/python/helpers_agents/fire_agents_help_launch.py +126 -0
  111. machineconfig/scripts/python/helpers_agents/fire_agents_helper_types.py +41 -0
  112. machineconfig/scripts/python/helpers_agents/templates/prompt.txt +10 -0
  113. machineconfig/scripts/python/helpers_agents/templates/template.ps1 +14 -0
  114. machineconfig/scripts/python/helpers_agents/templates/template.sh +32 -0
  115. machineconfig/scripts/python/{cloud_copy.py → helpers_cloud/cloud_copy.py} +30 -23
  116. machineconfig/scripts/python/{cloud_mount.py → helpers_cloud/cloud_mount.py} +29 -35
  117. machineconfig/scripts/python/{cloud_sync.py → helpers_cloud/cloud_sync.py} +12 -18
  118. machineconfig/scripts/python/{helpers → helpers_cloud}/helpers2.py +1 -1
  119. machineconfig/scripts/python/helpers_croshell/crosh.py +39 -0
  120. machineconfig/scripts/python/{start_slidev.py → helpers_croshell/start_slidev.py} +8 -9
  121. machineconfig/scripts/python/helpers_devops/cli_config.py +105 -0
  122. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +89 -0
  123. machineconfig/scripts/python/helpers_devops/cli_data.py +25 -0
  124. machineconfig/scripts/python/helpers_devops/cli_nw.py +214 -0
  125. machineconfig/scripts/python/helpers_devops/cli_repos.py +215 -0
  126. machineconfig/scripts/python/helpers_devops/cli_self.py +172 -0
  127. machineconfig/scripts/python/helpers_devops/cli_share_file.py +137 -0
  128. machineconfig/scripts/python/helpers_devops/cli_share_server.py +142 -0
  129. machineconfig/scripts/python/{share_terminal.py → helpers_devops/cli_share_terminal.py} +45 -35
  130. machineconfig/scripts/python/helpers_devops/cli_utils.py +96 -0
  131. machineconfig/scripts/python/{devops_backup_retrieve.py → helpers_devops/devops_backup_retrieve.py} +7 -10
  132. machineconfig/scripts/python/helpers_devops/devops_status.py +499 -0
  133. machineconfig/scripts/python/{devops_update_repos.py → helpers_devops/devops_update_repos.py} +68 -49
  134. machineconfig/scripts/python/helpers_devops/themes/choose_pwsh_theme.ps1 +81 -0
  135. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +3 -0
  136. machineconfig/scripts/python/{choose_wezterm_theme.py → helpers_devops/themes/choose_wezterm_theme.py} +3 -3
  137. machineconfig/scripts/python/helpers_fire_command/__init__.py +0 -0
  138. machineconfig/scripts/python/helpers_fire_command/f.py +0 -0
  139. machineconfig/scripts/python/{helpers/helpers4.py → helpers_fire_command/file_wrangler.py} +56 -20
  140. machineconfig/scripts/python/{fire_jobs_args_helper.py → helpers_fire_command/fire_jobs_args_helper.py} +5 -1
  141. machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +121 -0
  142. machineconfig/scripts/python/helpers_fire_command/fire_jobs_streamlit_helper.py +0 -0
  143. machineconfig/scripts/python/helpers_msearch/__init__.py +5 -0
  144. machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/fzfg +3 -3
  145. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfg.ps1 +59 -0
  146. machineconfig/scripts/python/helpers_navigator/__init__.py +20 -0
  147. machineconfig/scripts/python/helpers_navigator/command_builder.py +111 -0
  148. machineconfig/scripts/python/helpers_navigator/command_detail.py +44 -0
  149. machineconfig/scripts/python/helpers_navigator/command_tree.py +620 -0
  150. machineconfig/scripts/python/helpers_navigator/data_models.py +28 -0
  151. machineconfig/scripts/python/helpers_navigator/main_app.py +272 -0
  152. machineconfig/scripts/python/helpers_navigator/search_bar.py +15 -0
  153. machineconfig/scripts/python/helpers_network/__init__.py +0 -0
  154. machineconfig/scripts/python/helpers_network/address.py +132 -0
  155. machineconfig/scripts/python/{devops_add_identity.py → helpers_network/devops_add_identity.py} +0 -2
  156. machineconfig/scripts/python/helpers_network/devops_add_ssh_key.py +153 -0
  157. machineconfig/scripts/{linux → python/helpers_network}/mount_nfs +0 -1
  158. machineconfig/scripts/python/{mount_nfs.py → helpers_network/mount_nfs.py} +3 -3
  159. machineconfig/scripts/{linux → python/helpers_network}/mount_nw_drive +1 -2
  160. machineconfig/scripts/python/{mount_ssh.py → helpers_network/mount_ssh.py} +3 -3
  161. machineconfig/scripts/python/{onetimeshare.py → helpers_network/onetimeshare.py} +0 -1
  162. machineconfig/scripts/python/helpers_network/ssh_debug_linux.py +391 -0
  163. machineconfig/scripts/python/helpers_network/ssh_debug_windows.py +338 -0
  164. machineconfig/scripts/python/{wifi_conn.py → helpers_network/wifi_conn.py} +1 -53
  165. machineconfig/scripts/python/{wsl_windows_transfer.py → helpers_network/wsl_windows_transfer.py} +5 -4
  166. machineconfig/scripts/python/helpers_repos/action.py +209 -0
  167. machineconfig/scripts/python/helpers_repos/action_helper.py +150 -0
  168. machineconfig/scripts/python/{repos_helper_clone.py → helpers_repos/clone.py} +2 -3
  169. machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +218 -0
  170. machineconfig/scripts/python/{repos_helper.py → helpers_repos/entrypoint.py} +9 -17
  171. machineconfig/scripts/python/helpers_repos/grource.py +340 -0
  172. machineconfig/scripts/python/{repos_helper_record.py → helpers_repos/record.py} +4 -3
  173. machineconfig/scripts/python/helpers_repos/repo_analyzer_1.py +160 -0
  174. machineconfig/scripts/python/{count_lines.py → helpers_repos/repo_analyzer_2.py} +113 -192
  175. machineconfig/scripts/python/helpers_repos/sync.py +66 -0
  176. machineconfig/scripts/python/{repos_helper_update.py → helpers_repos/update.py} +3 -3
  177. machineconfig/scripts/python/helpers_sessions/__init__.py +0 -0
  178. machineconfig/scripts/python/helpers_sessions/sessions_multiprocess.py +65 -0
  179. machineconfig/scripts/python/helpers_utils/download.py +150 -0
  180. machineconfig/scripts/python/helpers_utils/path.py +185 -0
  181. machineconfig/scripts/python/interactive.py +64 -84
  182. machineconfig/scripts/python/mcfg_entry.py +58 -0
  183. machineconfig/scripts/python/msearch.py +71 -0
  184. machineconfig/scripts/python/sessions.py +119 -45
  185. machineconfig/scripts/python/terminal.py +133 -0
  186. machineconfig/scripts/python/utils.py +64 -0
  187. machineconfig/scripts/windows/mounts/Restore-ThunderbirdProfile.ps1 +92 -0
  188. machineconfig/scripts/windows/{mount_nfs.ps1 → mounts/mount_nfs.ps1} +1 -3
  189. machineconfig/scripts/windows/{mount_ssh.ps1 → mounts/mount_ssh.ps1} +1 -1
  190. machineconfig/scripts/windows/{share_smb.ps1 → mounts/share_smb.ps1} +0 -6
  191. machineconfig/scripts/windows/wrap_mcfg.ps1 +63 -0
  192. machineconfig/settings/broot/br.sh +0 -4
  193. machineconfig/settings/broot/conf.toml +1 -1
  194. machineconfig/settings/helix/config.toml +16 -0
  195. machineconfig/settings/helix/languages.toml +13 -4
  196. machineconfig/settings/helix/yazi-picker.sh +12 -0
  197. machineconfig/settings/lf/linux/exe/lfcd.sh +1 -0
  198. machineconfig/settings/lf/linux/exe/previewer.sh +9 -3
  199. machineconfig/settings/lf/linux/lfrc +10 -12
  200. machineconfig/settings/lf/windows/lfcd.ps1 +1 -1
  201. machineconfig/settings/lf/windows/lfrc +18 -38
  202. machineconfig/settings/lf/windows/mkfile.ps1 +1 -1
  203. machineconfig/settings/linters/.ruff.toml +1 -1
  204. machineconfig/settings/lvim/windows/archive/config_additional.lua +0 -6
  205. machineconfig/settings/marimo/marimo.toml +80 -0
  206. machineconfig/settings/marimo/snippets/globalize.py +34 -0
  207. machineconfig/settings/pistol/pistol.conf +1 -1
  208. machineconfig/settings/shells/bash/init.sh +82 -31
  209. machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +1 -1
  210. machineconfig/settings/shells/nushell/config.nu +2 -35
  211. machineconfig/settings/shells/nushell/env.nu +45 -6
  212. machineconfig/settings/shells/nushell/init.nu +314 -0
  213. machineconfig/settings/shells/pwsh/init.ps1 +61 -43
  214. machineconfig/settings/shells/starship/starship.toml +16 -0
  215. machineconfig/settings/shells/wezterm/wezterm.lua +2 -0
  216. machineconfig/settings/shells/wt/settings.json +32 -17
  217. machineconfig/settings/shells/zsh/init.sh +89 -0
  218. machineconfig/settings/svim/linux/init.toml +0 -4
  219. machineconfig/settings/svim/windows/init.toml +0 -3
  220. machineconfig/settings/television/cable_unix/alias.toml +8 -0
  221. machineconfig/settings/television/cable_unix/aws-buckets.toml +14 -0
  222. machineconfig/settings/television/cable_unix/aws-instances.toml +13 -0
  223. machineconfig/settings/television/cable_unix/bash-history.toml +8 -0
  224. machineconfig/settings/television/cable_unix/channels.toml +19 -0
  225. machineconfig/settings/television/cable_unix/dirs.toml +13 -0
  226. machineconfig/settings/television/cable_unix/distrobox-list.toml +42 -0
  227. machineconfig/settings/television/cable_unix/docker-images.toml +13 -0
  228. machineconfig/settings/television/cable_unix/dotfiles.toml +11 -0
  229. machineconfig/settings/television/cable_unix/env.toml +17 -0
  230. machineconfig/settings/television/cable_unix/files.toml +11 -0
  231. machineconfig/settings/television/cable_unix/fish-history.toml +8 -0
  232. machineconfig/settings/television/cable_unix/git-branch.toml +11 -0
  233. machineconfig/settings/television/cable_unix/git-diff.toml +10 -0
  234. machineconfig/settings/television/cable_unix/git-log.toml +12 -0
  235. machineconfig/settings/television/cable_unix/git-reflog.toml +12 -0
  236. machineconfig/settings/television/cable_unix/git-repos.toml +16 -0
  237. machineconfig/settings/television/cable_unix/guix.toml +20 -0
  238. machineconfig/settings/television/cable_unix/just-recipes.toml +18 -0
  239. machineconfig/settings/television/cable_unix/k8s-deployments.toml +36 -0
  240. machineconfig/settings/television/cable_unix/k8s-pods.toml +50 -0
  241. machineconfig/settings/television/cable_unix/k8s-services.toml +36 -0
  242. machineconfig/settings/television/cable_unix/man-pages.toml +24 -0
  243. machineconfig/settings/television/cable_unix/nu-history.toml +7 -0
  244. machineconfig/settings/television/cable_unix/procs.toml +20 -0
  245. machineconfig/settings/television/cable_unix/text.toml +17 -0
  246. machineconfig/settings/television/cable_unix/tldr.toml +18 -0
  247. machineconfig/settings/television/cable_unix/zsh-history.toml +9 -0
  248. machineconfig/settings/television/cable_windows/alias.toml +7 -0
  249. machineconfig/settings/television/cable_windows/dirs.toml +13 -0
  250. machineconfig/settings/television/cable_windows/docker-images.toml +13 -0
  251. machineconfig/settings/television/cable_windows/dotfiles.toml +11 -0
  252. machineconfig/settings/television/cable_windows/env.toml +17 -0
  253. machineconfig/settings/television/cable_windows/files.toml +14 -0
  254. machineconfig/settings/television/cable_windows/git-branch.toml +11 -0
  255. machineconfig/settings/television/cable_windows/git-diff.toml +10 -0
  256. machineconfig/settings/television/cable_windows/git-log.toml +11 -0
  257. machineconfig/settings/television/cable_windows/git-reflog.toml +11 -0
  258. machineconfig/settings/television/cable_windows/git-repos.toml +15 -0
  259. machineconfig/settings/television/cable_windows/nu-history.toml +7 -0
  260. machineconfig/settings/television/cable_windows/pwsh-history.toml +6 -0
  261. machineconfig/settings/television/cable_windows/text.toml +17 -0
  262. machineconfig/settings/yazi/init.lua +61 -0
  263. machineconfig/settings/yazi/keymap_linux.toml +94 -0
  264. machineconfig/settings/yazi/keymap_windows.toml +78 -0
  265. machineconfig/settings/yazi/shell/yazi_cd.ps1 +33 -0
  266. machineconfig/settings/yazi/shell/yazi_cd.sh +8 -0
  267. machineconfig/settings/yazi/theme.toml +4 -0
  268. machineconfig/settings/yazi/yazi_linux.toml +84 -0
  269. machineconfig/settings/yazi/yazi_windows.toml +58 -0
  270. machineconfig/setup_linux/__init__.py +11 -0
  271. machineconfig/setup_linux/apps_desktop.sh +89 -0
  272. machineconfig/setup_linux/apps_gui.sh +64 -0
  273. machineconfig/setup_linux/ssh/openssh_all.sh +25 -0
  274. machineconfig/setup_linux/ssh/openssh_wsl.sh +38 -0
  275. machineconfig/setup_linux/uv.sh +15 -0
  276. machineconfig/setup_linux/web_shortcuts/interactive.sh +26 -6
  277. machineconfig/setup_linux/web_shortcuts/live_from_github.sh +31 -0
  278. machineconfig/setup_mac/__init__.py +16 -0
  279. machineconfig/setup_mac/apps_gui.sh +248 -0
  280. machineconfig/setup_mac/ssh/openssh_setup.sh +114 -0
  281. machineconfig/setup_mac/uv.sh +36 -0
  282. machineconfig/setup_windows/__init__.py +11 -0
  283. machineconfig/setup_windows/others/power_options.ps1 +7 -0
  284. machineconfig/setup_windows/ssh/add-sshkey.ps1 +29 -0
  285. machineconfig/setup_windows/ssh/add_identity.ps1 +11 -0
  286. machineconfig/setup_windows/ssh/openssh-server.ps1 +37 -0
  287. machineconfig/setup_windows/uv.ps1 +17 -0
  288. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +27 -10
  289. machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +30 -0
  290. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +17 -0
  291. machineconfig/utils/accessories.py +7 -5
  292. machineconfig/utils/cloud/onedrive/README.md +139 -0
  293. machineconfig/utils/code.py +155 -105
  294. machineconfig/utils/files/art/fat_croco.txt +10 -0
  295. machineconfig/utils/files/art/halfwit_croco.txt +9 -0
  296. machineconfig/utils/files/art/happy_croco.txt +22 -0
  297. machineconfig/utils/files/art/water_croco.txt +11 -0
  298. machineconfig/utils/files/ascii_art.py +1 -1
  299. machineconfig/utils/files/dbms.py +257 -0
  300. machineconfig/utils/files/headers.py +11 -14
  301. machineconfig/utils/files/ouch/__init__.py +0 -0
  302. machineconfig/utils/files/ouch/decompress.py +45 -0
  303. machineconfig/utils/files/read.py +10 -18
  304. machineconfig/utils/installer_utils/github_release_bulk.py +156 -119
  305. machineconfig/utils/installer_utils/install_from_url.py +183 -0
  306. machineconfig/utils/installer_utils/installer_class.py +64 -181
  307. machineconfig/utils/installer_utils/installer_cli.py +175 -0
  308. machineconfig/utils/installer_utils/installer_helper.py +129 -0
  309. machineconfig/utils/installer_utils/{installer_abc.py → installer_locator_utils.py} +66 -97
  310. machineconfig/utils/{installer.py → installer_utils/installer_runner.py} +49 -82
  311. machineconfig/utils/io.py +77 -23
  312. machineconfig/utils/links.py +254 -162
  313. machineconfig/utils/meta.py +256 -0
  314. machineconfig/utils/notifications.py +1 -1
  315. machineconfig/utils/options.py +46 -18
  316. machineconfig/utils/options_tv.py +119 -0
  317. machineconfig/utils/path_extended.py +48 -101
  318. machineconfig/utils/path_helper.py +76 -23
  319. machineconfig/utils/procs.py +50 -70
  320. machineconfig/utils/scheduler.py +88 -124
  321. machineconfig/utils/scheduling.py +0 -3
  322. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
  323. machineconfig/utils/schemas/layouts/layout_types.py +1 -1
  324. machineconfig/utils/source_of_truth.py +3 -6
  325. machineconfig/utils/ssh.py +263 -274
  326. machineconfig/utils/ssh_utils/abc.py +5 -0
  327. machineconfig/utils/ssh_utils/copy_from_here.py +111 -0
  328. machineconfig/utils/ssh_utils/copy_to_here.py +302 -0
  329. machineconfig/utils/ssh_utils/utils.py +142 -0
  330. machineconfig/utils/ssh_utils/wsl.py +210 -0
  331. machineconfig/utils/terminal.py +3 -113
  332. machineconfig/utils/tst.py +20 -0
  333. machineconfig/utils/upgrade_packages.py +114 -28
  334. machineconfig/utils/ve.py +12 -4
  335. machineconfig-7.98.dist-info/METADATA +132 -0
  336. machineconfig-7.98.dist-info/RECORD +504 -0
  337. machineconfig-7.98.dist-info/entry_points.txt +13 -0
  338. machineconfig/cluster/sessions_managers/ffile.py +0 -4
  339. machineconfig/jobs/installer/linux_scripts/pgsql.sh +0 -49
  340. machineconfig/jobs/installer/linux_scripts/timescaledb.sh +0 -85
  341. machineconfig/jobs/linux/msc/cli_agents.sh +0 -16
  342. machineconfig/jobs/python/python_ve_symlink.py +0 -37
  343. machineconfig/jobs/python/vscode/api.py +0 -57
  344. machineconfig/jobs/python/vscode/sync_code.py +0 -73
  345. machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +0 -14
  346. machineconfig/jobs/windows/start_terminal.ps1 +0 -6
  347. machineconfig/jobs/windows/startup_file.cmd +0 -2
  348. machineconfig/profile/create.py +0 -303
  349. machineconfig/profile/shell.py +0 -176
  350. machineconfig/scripts/cloud/init.sh +0 -119
  351. machineconfig/scripts/linux/agents +0 -2
  352. machineconfig/scripts/linux/choose_wezterm_theme +0 -3
  353. machineconfig/scripts/linux/cloud_copy +0 -2
  354. machineconfig/scripts/linux/cloud_mount +0 -2
  355. machineconfig/scripts/linux/cloud_repo_sync +0 -2
  356. machineconfig/scripts/linux/cloud_sync +0 -2
  357. machineconfig/scripts/linux/croshell +0 -3
  358. machineconfig/scripts/linux/devops +0 -2
  359. machineconfig/scripts/linux/fire +0 -2
  360. machineconfig/scripts/linux/ftpx +0 -2
  361. machineconfig/scripts/linux/fzf2g +0 -21
  362. machineconfig/scripts/linux/fzfag +0 -17
  363. machineconfig/scripts/linux/fzffg +0 -25
  364. machineconfig/scripts/linux/fzfrga +0 -21
  365. machineconfig/scripts/linux/gh_models +0 -2
  366. machineconfig/scripts/linux/initai +0 -2
  367. machineconfig/scripts/linux/kill_process +0 -2
  368. machineconfig/scripts/linux/scheduler +0 -2
  369. machineconfig/scripts/linux/sessions +0 -2
  370. machineconfig/scripts/linux/share_smb +0 -1
  371. machineconfig/scripts/linux/skrg +0 -4
  372. machineconfig/scripts/linux/start_slidev +0 -2
  373. machineconfig/scripts/linux/start_terminals +0 -3
  374. machineconfig/scripts/linux/warp-cli.sh +0 -122
  375. machineconfig/scripts/linux/wifi_conn +0 -2
  376. machineconfig/scripts/linux/z_ls +0 -104
  377. machineconfig/scripts/python/ai/generate_files.py +0 -83
  378. machineconfig/scripts/python/ai/solutions/copilot/prompts/allLintersAndTypeCheckers.prompt.md +0 -5
  379. machineconfig/scripts/python/cloud_repo_sync.py +0 -190
  380. machineconfig/scripts/python/count_lines_frontend.py +0 -16
  381. machineconfig/scripts/python/devops_add_ssh_key.py +0 -120
  382. machineconfig/scripts/python/dotfile.py +0 -78
  383. machineconfig/scripts/python/fire_agents_help_launch.py +0 -120
  384. machineconfig/scripts/python/fire_agents_helper_types.py +0 -12
  385. machineconfig/scripts/python/fire_jobs_route_helper.py +0 -65
  386. machineconfig/scripts/python/get_zellij_cmd.py +0 -15
  387. machineconfig/scripts/python/gh_models.py +0 -104
  388. machineconfig/scripts/python/helpers/repo_sync_helpers.py +0 -116
  389. machineconfig/scripts/python/repos.py +0 -132
  390. machineconfig/scripts/python/repos_helper_action.py +0 -378
  391. machineconfig/scripts/python/snapshot.py +0 -25
  392. machineconfig/scripts/python/start_terminals.py +0 -121
  393. machineconfig/scripts/python/t4.py +0 -17
  394. machineconfig/scripts/windows/agents.ps1 +0 -1
  395. machineconfig/scripts/windows/choose_wezterm_theme.ps1 +0 -1
  396. machineconfig/scripts/windows/cloud_copy.ps1 +0 -1
  397. machineconfig/scripts/windows/cloud_mount.ps1 +0 -1
  398. machineconfig/scripts/windows/cloud_repo_sync.ps1 +0 -1
  399. machineconfig/scripts/windows/cloud_sync.ps1 +0 -1
  400. machineconfig/scripts/windows/croshell.ps1 +0 -1
  401. machineconfig/scripts/windows/devops.ps1 +0 -1
  402. machineconfig/scripts/windows/dotfile.ps1 +0 -1
  403. machineconfig/scripts/windows/fire.ps1 +0 -1
  404. machineconfig/scripts/windows/ftpx.ps1 +0 -1
  405. machineconfig/scripts/windows/fzfb.ps1 +0 -3
  406. machineconfig/scripts/windows/fzfg.ps1 +0 -2
  407. machineconfig/scripts/windows/fzfrga.bat +0 -20
  408. machineconfig/scripts/windows/gpt.ps1 +0 -1
  409. machineconfig/scripts/windows/grep.ps1 +0 -2
  410. machineconfig/scripts/windows/initai.ps1 +0 -1
  411. machineconfig/scripts/windows/kill_process.ps1 +0 -1
  412. machineconfig/scripts/windows/nano.ps1 +0 -3
  413. machineconfig/scripts/windows/pomodoro.ps1 +0 -1
  414. machineconfig/scripts/windows/reload_path.ps1 +0 -3
  415. machineconfig/scripts/windows/scheduler.ps1 +0 -1
  416. machineconfig/scripts/windows/sessions.ps1 +0 -1
  417. machineconfig/scripts/windows/snapshot.ps1 +0 -1
  418. machineconfig/scripts/windows/start_slidev.ps1 +0 -1
  419. machineconfig/scripts/windows/start_terminals.ps1 +0 -1
  420. machineconfig/scripts/windows/wifi_conn.ps1 +0 -2
  421. machineconfig/scripts/windows/wsl_rdp_windows_port_forwarding.ps1 +0 -46
  422. machineconfig/scripts/windows/wsl_ssh_windows_port_forwarding.ps1 +0 -76
  423. machineconfig/settings/lf/linux/exe/fzf_nano.sh +0 -16
  424. machineconfig/settings/lf/windows/fzf_edit.ps1 +0 -6
  425. machineconfig/settings/lf/windows/tst.ps1 +0 -1
  426. machineconfig/settings/yazi/yazi.toml +0 -4
  427. machineconfig/setup_linux/nix/cli_installation.sh +0 -157
  428. machineconfig/setup_linux/others/openssh-server_add_pub_key.sh +0 -57
  429. machineconfig/setup_linux/web_shortcuts/croshell.sh +0 -11
  430. machineconfig/setup_linux/web_shortcuts/ssh.sh +0 -52
  431. machineconfig/setup_windows/web_shortcuts/all.ps1 +0 -18
  432. machineconfig/setup_windows/web_shortcuts/ascii_art.ps1 +0 -36
  433. machineconfig/setup_windows/web_shortcuts/croshell.ps1 +0 -16
  434. machineconfig/setup_windows/web_shortcuts/ssh.ps1 +0 -11
  435. machineconfig/utils/ai/generate_file_checklist.py +0 -68
  436. machineconfig/utils/installer_utils/installer.py +0 -189
  437. machineconfig-5.15.dist-info/METADATA +0 -188
  438. machineconfig-5.15.dist-info/RECORD +0 -415
  439. machineconfig-5.15.dist-info/entry_points.txt +0 -18
  440. machineconfig/cluster/sessions_managers/{utils → helpers}/load_balancer_helper.py +0 -0
  441. machineconfig/scripts/linux/{share_nfs → other/share_nfs} +0 -0
  442. machineconfig/scripts/linux/{start_docker → other/start_docker} +0 -0
  443. machineconfig/scripts/linux/{switch_ip → other/switch_ip} +0 -0
  444. machineconfig/{jobs/python → scripts/python/ai/utils}/__init__.py +0 -0
  445. machineconfig/scripts/python/{helpers → helpers_agents}/__init__.py +0 -0
  446. machineconfig/{jobs/windows/msc/cli_agents.bat → scripts/python/helpers_agents/agentic_frameworks/__init__.py} +0 -0
  447. machineconfig/scripts/python/{fire_agents_help_search.py → helpers_agents/fire_agents_help_search.py} +0 -0
  448. machineconfig/scripts/python/{fire_agents_load_balancer.py → helpers_agents/fire_agents_load_balancer.py} +0 -0
  449. machineconfig/{jobs/windows/msc/cli_agents.ps1 → scripts/python/helpers_cloud/__init__.py} +0 -0
  450. machineconfig/scripts/python/{helpers → helpers_cloud}/cloud_helpers.py +1 -1
  451. /machineconfig/scripts/python/{helpers → helpers_cloud}/helpers5.py +0 -0
  452. /machineconfig/scripts/python/{fire_jobs_streamlit_helper.py → helpers_croshell/__init__.py} +0 -0
  453. /machineconfig/scripts/python/{pomodoro.py → helpers_croshell/pomodoro.py} +0 -0
  454. /machineconfig/scripts/python/{scheduler.py → helpers_croshell/scheduler.py} +0 -0
  455. /machineconfig/scripts/python/{viewer.py → helpers_croshell/viewer.py} +0 -0
  456. /machineconfig/scripts/python/{viewer_template.py → helpers_croshell/viewer_template.py} +0 -0
  457. /machineconfig/scripts/{windows/share_nfs.ps1 → python/helpers_devops/__init__.py} +0 -0
  458. /machineconfig/{settings/shells/pwsh/profile.ps1 → scripts/python/helpers_devops/themes/__init__.py} +0 -0
  459. /machineconfig/{settings/yazi/keymap.toml → scripts/python/helpers_devops/themes/choose_starship_theme.ps1} +0 -0
  460. /machineconfig/scripts/python/{cloud_manager.py → helpers_fire_command/cloud_manager.py} +0 -0
  461. /machineconfig/scripts/{linux → python/helpers_network}/mount_drive +0 -0
  462. /machineconfig/scripts/python/{mount_nw_drive.py → helpers_network/mount_nw_drive.py} +0 -0
  463. /machineconfig/scripts/{linux → python/helpers_network}/mount_smb +0 -0
  464. /machineconfig/scripts/windows/{mount_nw.ps1 → mounts/mount_nw.ps1} +0 -0
  465. /machineconfig/scripts/windows/{mount_smb.ps1 → mounts/mount_smb.ps1} +0 -0
  466. /machineconfig/scripts/windows/{share_cloud.cmd → mounts/share_cloud.cmd} +0 -0
  467. /machineconfig/scripts/windows/{unlock_bitlocker.ps1 → mounts/unlock_bitlocker.ps1} +0 -0
  468. /machineconfig/setup_linux/{web_shortcuts → others}/android.sh +0 -0
  469. /machineconfig/{jobs/windows/archive → setup_windows/ssh}/openssh-server_add_key.ps1 +0 -0
  470. /machineconfig/{jobs/windows/archive → setup_windows/ssh}/openssh-server_copy-ssh-id.ps1 +0 -0
  471. {machineconfig-5.15.dist-info → machineconfig-7.98.dist-info}/WHEEL +0 -0
  472. {machineconfig-5.15.dist-info → machineconfig-7.98.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,183 @@
1
+
2
+
3
+ import platform
4
+ from typing import TYPE_CHECKING, Optional
5
+
6
+ from machineconfig.utils.installer_utils.installer_helper import install_deb_package, download_and_prepare
7
+ from machineconfig.utils.installer_utils.installer_locator_utils import find_move_delete_linux, find_move_delete_windows
8
+ from machineconfig.utils.installer_utils.github_release_bulk import (
9
+ get_repo_name_from_url,
10
+ fetch_github_release_data,
11
+ extract_release_info,
12
+ AssetInfo,
13
+ )
14
+ from machineconfig.utils.path_extended import PathExtended
15
+ from machineconfig.utils.source_of_truth import INSTALL_VERSION_ROOT
16
+
17
+ if TYPE_CHECKING:
18
+ from rich.console import Console
19
+
20
+ SUPPORTED_GITHUB_HOSTS = {"github.com", "www.github.com"}
21
+
22
+
23
+ def _format_size(size_bytes: int) -> str:
24
+ if size_bytes <= 0:
25
+ return "0 B"
26
+ units = ("B", "KiB", "MiB", "GiB", "TiB")
27
+ value = float(size_bytes)
28
+ index = 0
29
+ while value >= 1024 and index < len(units) - 1:
30
+ value /= 1024
31
+ index += 1
32
+ return f"{value:.1f} {units[index]}"
33
+
34
+
35
+ def _derive_tool_name(repo_name: str, asset_name: Optional[str]) -> Optional[str]:
36
+ repo_segment = repo_name.split("/", maxsplit=1)[-1]
37
+ repo_clean = repo_segment.replace(".git", "").lower()
38
+ repo_filtered = "".join(char for char in repo_clean if char.isalnum())
39
+ if repo_filtered:
40
+ return repo_filtered
41
+ if asset_name is None:
42
+ return None
43
+ asset_clean = asset_name.lower()
44
+ asset_filtered = "".join(char for char in asset_clean if char.isalnum())
45
+ if asset_filtered:
46
+ return asset_filtered
47
+ return None
48
+
49
+
50
+ def _finalize_install(repo_name: str, asset_name: Optional[str], version: str, extracted_path: PathExtended, console: "Console") -> None:
51
+ from rich.panel import Panel
52
+ if extracted_path.suffix == ".deb":
53
+ install_deb_package(extracted_path)
54
+ tool_name_deb = _derive_tool_name(repo_name, asset_name)
55
+ if tool_name_deb is not None:
56
+ INSTALL_VERSION_ROOT.joinpath(tool_name_deb).parent.mkdir(parents=True, exist_ok=True)
57
+ INSTALL_VERSION_ROOT.joinpath(tool_name_deb).write_text(version, encoding="utf-8")
58
+ console.print(Panel(f"Installed Debian package for [green]{tool_name_deb}[/green]", title="✅ Complete", border_style="green"))
59
+ return
60
+ system_name = platform.system()
61
+ tool_name = _derive_tool_name(repo_name, asset_name)
62
+ rename_target = f"{tool_name}.exe" if system_name == "Windows" else tool_name
63
+ try:
64
+ if system_name == "Windows":
65
+ installed_path = find_move_delete_windows(downloaded_file_path=extracted_path, tool_name=tool_name, delete=True, rename_to=rename_target)
66
+ elif system_name in {"Linux", "Darwin"}:
67
+ installed_path = find_move_delete_linux(downloaded=extracted_path, tool_name=tool_name, delete=True, rename_to=rename_target)
68
+ else:
69
+ console.print(Panel(f"Unsupported operating system: {system_name}", title="❌ Error", border_style="red"))
70
+ return None
71
+ except IndexError:
72
+ if system_name == "Windows":
73
+ installed_path = find_move_delete_windows(downloaded_file_path=extracted_path, tool_name=None, delete=True, rename_to=rename_target)
74
+ elif system_name in {"Linux", "Darwin"}:
75
+ installed_path = find_move_delete_linux(downloaded=extracted_path, tool_name="", delete=True, rename_to=rename_target)
76
+ else:
77
+ raise
78
+ if tool_name is not None:
79
+ INSTALL_VERSION_ROOT.joinpath(tool_name).parent.mkdir(parents=True, exist_ok=True)
80
+ INSTALL_VERSION_ROOT.joinpath(tool_name).write_text(version, encoding="utf-8")
81
+ console.print(Panel(f"Installed [green]{tool_name}[/green] to {installed_path}\nVersion: {version}", title="✅ Complete", border_style="green"))
82
+
83
+
84
+ def install_from_github_url(github_url: str) -> None:
85
+ from machineconfig.utils.options import choose_from_options
86
+ from rich.console import Console
87
+ from rich.panel import Panel
88
+
89
+ console = Console()
90
+ repo_info = get_repo_name_from_url(github_url)
91
+ if repo_info is None:
92
+ console.print(Panel(f"Invalid GitHub URL: {github_url}", title="❌ Error", border_style="red"))
93
+ return None
94
+ owner, repo = repo_info
95
+ repo_name = f"{owner}/{repo}"
96
+ console.print(Panel(f"Fetching latest release for [green]{repo_name}[/green]", title="🌐 GitHub", border_style="blue"))
97
+ release_raw = fetch_github_release_data(owner, repo)
98
+ if not release_raw:
99
+ console.print(Panel("No releases available for this repository.", title="❌ Error", border_style="red"))
100
+ return None
101
+
102
+ release_info = extract_release_info(release_raw)
103
+ if not release_info:
104
+ console.print(Panel("Failed to parse release information.", title="❌ Error", border_style="red"))
105
+ return None
106
+
107
+ assets = release_info["assets"]
108
+ if not assets:
109
+ console.print(Panel("No downloadable assets found in the latest release.", title="❌ Error", border_style="red"))
110
+ return None
111
+ binary_assets = assets
112
+ selection_pool = binary_assets if binary_assets else assets
113
+ if not selection_pool:
114
+ console.print(Panel("No assets available for installation.", title="❌ Error", border_style="red"))
115
+ return None
116
+
117
+ # First pass: collect all formatted data and calculate column widths
118
+ asset_data = []
119
+ for asset in selection_pool:
120
+ name = asset["name"]
121
+ download_url = asset["browser_download_url"]
122
+ if name == "" or download_url == "":
123
+ continue
124
+ size = asset["size"]
125
+ download_count = asset.get("download_count", 0)
126
+ created_at = asset.get("created_at", "")
127
+
128
+ # Format each field
129
+ size_str = f"[{_format_size(size)}]"
130
+ downloads_str = f"{download_count:,}"
131
+ date_str = created_at.split("T")[0] if created_at else "N/A"
132
+
133
+ asset_data.append({
134
+ "name": name,
135
+ "size_str": size_str,
136
+ "downloads_str": downloads_str,
137
+ "date_str": date_str,
138
+ "asset": asset
139
+ })
140
+
141
+ # Calculate maximum widths for alignment
142
+ max_name_len = max(len(item["name"]) for item in asset_data) if asset_data else 0
143
+ max_size_len = max(len(item["size_str"]) for item in asset_data) if asset_data else 0
144
+ max_downloads_len = max(len(item["downloads_str"]) for item in asset_data) if asset_data else 0
145
+
146
+ # Second pass: build aligned labels
147
+ options_map: dict[str, AssetInfo] = {}
148
+ for item in asset_data:
149
+ name_padded = item["name"].ljust(max_name_len)
150
+ size_padded = item["size_str"].ljust(max_size_len)
151
+ downloads_padded = item["downloads_str"].rjust(max_downloads_len)
152
+
153
+ label = f"{name_padded} {size_padded} | ⬇ {downloads_padded} | 📅 {item['date_str']}"
154
+ options_map[label] = item["asset"]
155
+
156
+ if not options_map:
157
+ console.print(Panel("Release assets lack download URLs.", title="❌ Error", border_style="red"))
158
+ return None
159
+ selection_label = choose_from_options(options=list(options_map.keys()), msg="Select a release asset", multi=False, header="📦 GitHub Release Assets", tv=True)
160
+ selected_asset = options_map[selection_label]
161
+ download_url_value = selected_asset["browser_download_url"]
162
+ asset_name_value = selected_asset["name"]
163
+ if download_url_value == "":
164
+ console.print(Panel("Selected asset lacks a download URL.", title="❌ Error", border_style="red"))
165
+ return None
166
+ asset_name = asset_name_value if asset_name_value != "" else "github_binary"
167
+ version = release_info["tag_name"] if release_info["tag_name"] != "" else "latest"
168
+ console.print(Panel(f"Downloading [cyan]{asset_name}[/cyan]", title="⬇️ Download", border_style="magenta"))
169
+ extracted_path = download_and_prepare(download_url_value)
170
+ _finalize_install(repo_name=repo_name, asset_name=asset_name, version=version, extracted_path=extracted_path, console=console)
171
+
172
+
173
+ def install_from_binary_url(binary_url: str) -> None:
174
+ from rich.console import Console
175
+ # from rich.panel import Panel
176
+ console = Console()
177
+ # parsed = urlparse(binary_url)
178
+ # asset_candidate = parsed.path.split("/")[-1] if parsed.path else ""
179
+ # asset_name = asset_candidate if asset_candidate != "" else "binary_asset"
180
+ # host = parsed.netloc if parsed.netloc != "" else "remote host"
181
+ # console.print(Panel(f"Downloading from [green]{binary_url}[/green]", title="⬇️ Download", border_style="magenta"))
182
+ extracted_path = download_and_prepare(binary_url)
183
+ _finalize_install(repo_name="", asset_name=None, version="latest", extracted_path=extracted_path, console=console)
@@ -1,16 +1,16 @@
1
+ from machineconfig.utils.installer_utils.installer_helper import install_deb_package, download_and_prepare
1
2
  from machineconfig.utils.path_extended import PathExtended
2
- from machineconfig.utils.installer_utils.installer_abc import find_move_delete_linux, find_move_delete_windows
3
- from machineconfig.utils.source_of_truth import INSTALL_TMP_DIR, INSTALL_VERSION_ROOT, LIBRARY_ROOT
4
- from machineconfig.utils.installer_utils.installer_abc import check_tool_exists
5
- from machineconfig.utils.io import read_json
6
- from machineconfig.utils.schemas.installer.installer_types import InstallerData, InstallerDataFiles, get_os_name, get_normalized_arch
3
+ from machineconfig.utils.source_of_truth import INSTALL_VERSION_ROOT
4
+ from machineconfig.utils.installer_utils.installer_locator_utils import find_move_delete_linux, find_move_delete_windows, check_tool_exists
5
+ from machineconfig.utils.schemas.installer.installer_types import InstallerData, get_os_name, get_normalized_arch
6
+ from machineconfig.utils.installer_utils.github_release_bulk import (
7
+ get_repo_name_from_url,
8
+ get_release_info,
9
+ )
7
10
 
8
11
  import platform
9
12
  import subprocess
10
- import json
11
- from typing import Optional, Any
12
- from pathlib import Path
13
- from urllib.parse import urlparse
13
+ from typing import Optional
14
14
 
15
15
 
16
16
  class Installer:
@@ -32,64 +32,21 @@ class Installer:
32
32
 
33
33
  def _get_exe_name(self) -> str:
34
34
  """Derive executable name from app name by converting to lowercase and removing spaces."""
35
- return self.installer_data["appName"].lower().replace(" ", "").replace("-", "")
36
-
37
- @staticmethod
38
- def choose_app_and_install():
39
- print(f"\n{'=' * 80}\n🔍 SELECT APPLICATION TO INSTALL 🔍\n{'=' * 80}")
40
- from machineconfig.utils.options import choose_from_options
41
-
42
- print("📂 Searching for configuration files...")
43
- jobs_dir = Path(LIBRARY_ROOT.joinpath("jobs"))
44
- config_paths = [Path(p) for p in jobs_dir.rglob("config.json")]
45
- path = choose_from_options(multi=False, options=config_paths, msg="Choose one option")
46
- print(f"📄 Loading configuration from: {path}")
47
- config_data = read_json(path)
48
- installer_data_files = InstallerDataFiles(config_data)
49
-
50
- # Extract app names from the installers
51
- app_names = [installer["appName"] for installer in installer_data_files["installers"]]
52
- print("🔍 Select an application to install:")
53
- app_name = choose_from_options(multi=False, options=app_names, fzf=True, msg="Choose one option")
54
-
55
- # Find the selected installer data
56
- selected_installer_data = None
57
- for installer_data in installer_data_files["installers"]:
58
- if installer_data["appName"] == app_name:
59
- selected_installer_data = installer_data
60
- break
61
-
62
- if selected_installer_data is None:
63
- raise ValueError(f"Could not find installer data for {app_name}")
64
-
65
- installer = Installer(installer_data=selected_installer_data)
66
- exe_name = installer._get_exe_name()
67
- print(f"📦 Selected application: {exe_name}")
68
- version = input(f"📝 Enter version to install for {exe_name} [latest]: ") or None
69
- print(f"\n{'=' * 80}\n🚀 INSTALLING {exe_name.upper()} 🚀\n{'=' * 80}")
70
- installer.install(version=version)
35
+ return self.installer_data["appName"].lower().replace(" ", "") # .replace("-", "")
71
36
 
72
37
  def install_robust(self, version: Optional[str]) -> str:
73
38
  try:
74
39
  exe_name = self._get_exe_name()
75
- print(f"\n{'=' * 80}\n🚀 INSTALLING {exe_name.upper()} 🚀\n{'=' * 80}")
76
40
  result_old = subprocess.run(f"{exe_name} --version", shell=True, capture_output=True, text=True)
77
41
  old_version_cli = result_old.stdout.strip()
78
- print(f"📊 Current version: {old_version_cli or 'Not installed'}")
79
-
42
+ print(f"🚀 INSTALLING {exe_name.upper()} 🚀. 📊 Current version: {old_version_cli or 'Not installed'}")
80
43
  self.install(version=version)
81
-
82
44
  result_new = subprocess.run(f"{exe_name} --version", shell=True, capture_output=True, text=True)
83
45
  new_version_cli = result_new.stdout.strip()
84
- print(f"📊 New version: {new_version_cli}")
85
-
86
46
  if old_version_cli == new_version_cli:
87
- print(f"ℹ️ Same version detected: {old_version_cli}")
88
47
  return f"""📦️ 😑 {exe_name}, same version: {old_version_cli}"""
89
48
  else:
90
- print(f"🚀 Update successful: {old_version_cli} ➡️ {new_version_cli}")
91
49
  return f"""📦️ 🤩 {exe_name} updated from {old_version_cli} ➡️ TO ➡️ {new_version_cli}"""
92
-
93
50
  except Exception as ex:
94
51
  exe_name = self._get_exe_name()
95
52
  app_name = self.installer_data["appName"]
@@ -104,28 +61,27 @@ class Installer:
104
61
  installer_arch_os = self.installer_data["fileNamePattern"][arch][os_name]
105
62
  if installer_arch_os is None:
106
63
  raise ValueError(f"No installation pattern for {exe_name} on {os_name} {arch}")
107
-
108
- print(f"\n{'=' * 80}\n🔧 INSTALLATION PROCESS: {exe_name} 🔧\n{'=' * 80}")
109
64
  version_to_be_installed: str = "unknown" # Initialize to ensure it's always bound
110
65
  if repo_url == "CMD":
111
- if "npm " in installer_arch_os or "pip " in installer_arch_os or "winget " in installer_arch_os:
66
+ if any(pm in installer_arch_os for pm in ["npm ", "pip ", "winget ", "brew ", "curl "]):
67
+ from rich import print as rprint
68
+ from rich.panel import Panel
69
+ from rich.console import Group
112
70
  package_manager = installer_arch_os.split(" ", maxsplit=1)[0]
113
- print(f"📦 Using package manager: {package_manager}")
71
+ print(f"📦 Using package manager: {installer_arch_os}")
114
72
  desc = package_manager + " installation"
115
73
  version_to_be_installed = package_manager + "Latest"
116
- print(f"🚀 Running: {installer_arch_os}")
117
- result = subprocess.run(installer_arch_os, shell=True, capture_output=True, text=True)
74
+ result = subprocess.run(installer_arch_os, shell=True, capture_output=False, text=True)
118
75
  success = result.returncode == 0 and result.stderr == ""
119
76
  if not success:
120
- print(f"❌ {desc} failed")
77
+ sub_panels = []
121
78
  if result.stdout:
122
- print(f"STDOUT: {result.stdout}")
79
+ sub_panels.append(Panel(result.stdout, title="STDOUT", style="blue"))
123
80
  if result.stderr:
124
- print(f"STDERR: {result.stderr}")
125
- print(f"Return code: {result.returncode}")
126
- print(f"✅ Package manager installation completed\n{'=' * 80}")
81
+ sub_panels.append(Panel(result.stderr, title="STDERR", style="red"))
82
+ group_content = Group(f" {desc} failed\nReturn code: {result.returncode}", *sub_panels)
83
+ rprint(Panel(group_content, title=desc, style="red"))
127
84
  elif installer_arch_os.endswith((".sh", ".py", ".ps1")):
128
- # search for the script, see which path ends with the script name
129
85
  import machineconfig.jobs.installer as module
130
86
  from pathlib import Path
131
87
  search_root = Path(module.__file__).parent
@@ -139,34 +95,22 @@ class Installer:
139
95
  if installer_arch_os.endswith(".sh"):
140
96
  if platform.system() not in ["Linux", "Darwin"]:
141
97
  raise NotImplementedError(f"Shell script installation not supported on {platform.system()}")
142
- print(f"🚀 Running shell script: {installer_path}")
143
98
  subprocess.run(f"bash {installer_path}", shell=True, check=True)
144
99
  version_to_be_installed = "scripted_installation"
145
- print(f"✅ Shell script installation completed\n{'=' * 80}")
146
100
  elif installer_arch_os.endswith(".ps1"):
147
101
  if platform.system() != "Windows":
148
102
  raise NotImplementedError(f"PowerShell script installation not supported on {platform.system()}")
149
- print(f"🚀 Running PowerShell script: {installer_path}")
150
103
  subprocess.run(f"powershell -ExecutionPolicy Bypass -File {installer_path}", shell=True, check=True)
151
104
  version_to_be_installed = "scripted_installation"
152
- print(f"✅ PowerShell script installation completed\n{'=' * 80}")
153
105
  elif installer_arch_os.endswith(".py"):
154
106
  import runpy
155
107
  runpy.run_path(str(installer_path), run_name=None)["main"](self.installer_data, version=version)
156
108
  version_to_be_installed = str(version)
157
- print(f" Custom installation completed\n{'=' * 80}")
158
- elif installer_arch_os.startswith("https://"): # its a url to be downloaded
159
- print(f"📥 Downloading object from URL: {installer_arch_os}")
160
- downloaded_object = PathExtended(installer_arch_os).download(folder=INSTALL_TMP_DIR)
161
- # object is either a zip containing a binary or a straight out binary.
162
- if downloaded_object.suffix in [".zip", ".tar.gz"]:
163
- print(f"📦 Decompressing downloaded archive: {downloaded_object}")
164
- downloaded_object = downloaded_object.decompress()
165
- print(f"✅ Decompression completed to: {downloaded_object}")
109
+ elif installer_arch_os.startswith("https://") or installer_arch_os.startswith("http://"):
110
+ downloaded_object = download_and_prepare(installer_arch_os)
166
111
  if downloaded_object.suffix in [".exe", ""]: # likely an executable
167
112
  if platform.system() == "Windows":
168
- print("🪟 Installing on Windows...")
169
- exe = find_move_delete_windows(downloaded_file_path=downloaded_object, exe_name=exe_name, delete=True, rename_to=exe_name.replace(".exe", "") + ".exe")
113
+ exe = find_move_delete_windows(downloaded_file_path=downloaded_object, tool_name=exe_name, delete=True, rename_to=exe_name.replace(".exe", "") + ".exe")
170
114
  elif platform.system() in ["Linux", "Darwin"]:
171
115
  system_name = "Linux" if platform.system() == "Linux" else "macOS"
172
116
  print(f"🐧 Installing on {system_name}...")
@@ -175,7 +119,6 @@ class Installer:
175
119
  error_msg = f"❌ ERROR: System {platform.system()} not supported"
176
120
  print(error_msg)
177
121
  raise NotImplementedError(error_msg)
178
-
179
122
  _ = exe
180
123
  if exe.name.replace(".exe", "") != exe_name.replace(".exe", ""):
181
124
  from rich import print as pprint
@@ -186,33 +129,20 @@ class Installer:
186
129
  print(f"🔄 Renaming to correct name: {new_exe_name}")
187
130
  exe.with_name(name=new_exe_name, inplace=True, overwrite=True)
188
131
  version_to_be_installed = "downloaded_binary"
189
- print(f"✅ Downloaded binary installation completed\n{'=' * 80}")
132
+ elif downloaded_object.suffix in [".deb"]:
133
+ install_deb_package(downloaded_object)
134
+ version_to_be_installed = "downloaded_deb"
135
+ else:
136
+ raise ValueError(f"Downloaded file is not an executable: {downloaded_object}")
190
137
  else:
191
138
  raise NotImplementedError(f"CMD installation method not implemented for: {installer_arch_os}")
192
139
  else:
193
140
  assert repo_url.startswith("https://github.com/"), f"repoURL must be a GitHub URL, got {repo_url}"
194
- print("📥 Downloading from repository...")
195
- downloaded, version_to_be_installed = self.download(version=version)
196
- if str(downloaded).endswith(".deb"):
197
- print(f"📦 Installing .deb package: {downloaded}")
198
- assert platform.system() == "Linux"
199
- result = subprocess.run(f"sudo nala install -y {downloaded}", shell=True, capture_output=True, text=True)
200
- success = result.returncode == 0 and result.stderr == ""
201
- if not success:
202
- desc = "Installing .deb"
203
- print(f"❌ {desc} failed")
204
- if result.stdout:
205
- print(f"STDOUT: {result.stdout}")
206
- if result.stderr:
207
- print(f"STDERR: {result.stderr}")
208
- print(f"Return code: {result.returncode}")
209
- print("🗑️ Cleaning up .deb package...")
210
- downloaded.delete(sure=True)
211
- print(f"✅ DEB package installation completed\n{'=' * 80}")
141
+ downloaded, version_to_be_installed = self.binary_download(version=version)
142
+ if str(downloaded).endswith(".deb"): install_deb_package(downloaded)
212
143
  else:
213
144
  if platform.system() == "Windows":
214
- print("🪟 Installing on Windows...")
215
- exe = find_move_delete_windows(downloaded_file_path=downloaded, exe_name=exe_name, delete=True, rename_to=exe_name.replace(".exe", "") + ".exe")
145
+ exe = find_move_delete_windows(downloaded_file_path=downloaded, tool_name=exe_name, delete=True, rename_to=exe_name.replace(".exe", "") + ".exe")
216
146
  elif platform.system() in ["Linux", "Darwin"]:
217
147
  system_name = "Linux" if platform.system() == "Linux" else "macOS"
218
148
  print(f"🐧 Installing on {system_name}...")
@@ -221,33 +151,24 @@ class Installer:
221
151
  error_msg = f"❌ ERROR: System {platform.system()} not supported"
222
152
  print(error_msg)
223
153
  raise NotImplementedError(error_msg)
224
-
225
154
  _ = exe
226
155
  if exe.name.replace(".exe", "") != exe_name.replace(".exe", ""):
227
156
  from rich import print as pprint
228
157
  from rich.panel import Panel
229
-
230
158
  print("⚠️ Warning: Executable name mismatch")
231
159
  pprint(Panel(f"Expected exe name: [red]{exe_name}[/red] \nAttained name: [red]{exe.name.replace('.exe', '')}[/red]", title="exe name mismatch", subtitle=repo_url))
232
160
  new_exe_name = exe_name + ".exe" if platform.system() == "Windows" else exe_name
233
161
  print(f"🔄 Renaming to correct name: {new_exe_name}")
234
162
  exe.with_name(name=new_exe_name, inplace=True, overwrite=True)
235
-
236
- print(f"💾 Saving version information to: {INSTALL_VERSION_ROOT.joinpath(exe_name)}")
237
163
  INSTALL_VERSION_ROOT.joinpath(exe_name).parent.mkdir(parents=True, exist_ok=True)
238
164
  INSTALL_VERSION_ROOT.joinpath(exe_name).write_text(version_to_be_installed or "unknown", encoding="utf-8")
239
- print(f"✅ Installation completed successfully!\n{'=' * 80}")
240
-
241
- def download(self, version: Optional[str]) -> tuple[PathExtended, str]:
165
+ def binary_download(self, version: Optional[str]) -> tuple[PathExtended, str]:
242
166
  exe_name = self._get_exe_name()
243
167
  repo_url = self.installer_data["repoURL"]
244
- app_name = self.installer_data["appName"]
245
- print(f"\n{'=' * 80}\n📥 DOWNLOADING: {exe_name} 📥\n{'=' * 80}")
246
-
168
+ # app_name = self.installer_data["appName"]
247
169
  download_link: Optional[str] = None
248
170
  version_to_be_installed: Optional[str] = None
249
-
250
- if "github" not in repo_url or ".zip" in repo_url or ".tar.gz" in repo_url:
171
+ if "github" not in repo_url:
251
172
  # Direct download URL
252
173
  download_link = repo_url
253
174
  version_to_be_installed = "predefined_url"
@@ -259,71 +180,19 @@ class Installer:
259
180
  arch = get_normalized_arch()
260
181
  os_name = get_os_name()
261
182
  print(f"🧭 Detected system={os_name} arch={arch}")
262
-
263
183
  # Use existing get_github_release method to get download link and version
264
184
  download_link, version_to_be_installed = self.get_github_release(repo_url, version)
265
-
185
+ # print(f"🌟 Retrieved download link from GitHub: {download_link}")
186
+ # print(f"📦 Version to be installed: {version_to_be_installed}")
266
187
  if download_link is None:
267
188
  raise ValueError(f"Could not retrieve download link for {exe_name} version {version or 'latest'}")
268
-
269
189
  print(f"📦 Version to be installed: {version_to_be_installed}")
270
190
  print(f"🔗 Download URL: {download_link}")
271
-
272
191
  assert download_link is not None, "download_link must be set"
273
192
  assert version_to_be_installed is not None, "version_to_be_installed must be set"
274
- print(f"📥 Downloading {app_name} from: {download_link}")
275
- downloaded = PathExtended(download_link).download(folder=INSTALL_TMP_DIR).decompress()
276
- print(f"✅ Download and extraction completed to: {downloaded}\n{'=' * 80}")
193
+ downloaded = download_and_prepare(download_link)
277
194
  return downloaded, version_to_be_installed
278
195
 
279
- # --------------------------- Arch / template helpers ---------------------------
280
-
281
- @staticmethod
282
- def _get_repo_name_from_url(repo_url: str) -> str:
283
- """Extract owner/repo from GitHub URL."""
284
- try:
285
- parsed = urlparse(repo_url)
286
- path_parts = parsed.path.strip("/").split("/")
287
- return f"{path_parts[0]}/{path_parts[1]}"
288
- except (IndexError, AttributeError):
289
- return ""
290
-
291
- @staticmethod
292
- def _fetch_github_release_data(repo_name: str, version: Optional[str] = None) -> Optional[dict[str, Any]]:
293
- """Fetch release data from GitHub API using requests."""
294
- import requests
295
-
296
- try:
297
- if version and version.lower() != "latest":
298
- # Fetch specific version
299
- url = f"https://api.github.com/repos/{repo_name}/releases/tags/{version}"
300
- else:
301
- # Fetch latest release
302
- url = f"https://api.github.com/repos/{repo_name}/releases/latest"
303
-
304
- response = requests.get(url, timeout=30)
305
-
306
- if response.status_code != 200:
307
- print(f"❌ Failed to fetch data for {repo_name}: HTTP {response.status_code}")
308
- return None
309
-
310
- response_data = response.json()
311
-
312
- # Check if API returned an error
313
- if "message" in response_data:
314
- if "API rate limit exceeded" in response_data.get("message", ""):
315
- print(f"🚫 Rate limit exceeded for {repo_name}")
316
- return None
317
- elif "Not Found" in response_data.get("message", ""):
318
- print(f"🔍 No releases found for {repo_name}")
319
- return None
320
-
321
- return response_data
322
-
323
- except (requests.RequestException, requests.Timeout, json.JSONDecodeError) as e:
324
- print(f"❌ Error fetching {repo_name}: {e}")
325
- return None
326
-
327
196
  def get_github_release(self, repo_url: str, version: Optional[str]) -> tuple[Optional[str], Optional[str]]:
328
197
  """
329
198
  Get download link and version from GitHub release based on fileNamePattern.
@@ -334,25 +203,39 @@ class Installer:
334
203
  filename_pattern = self.installer_data["fileNamePattern"][arch][os_name]
335
204
  if filename_pattern is None:
336
205
  raise ValueError(f"No fileNamePattern for {self._get_exe_name()} on {os_name} {arch}")
337
- repo_name = self._get_repo_name_from_url(repo_url)
338
- if not repo_name:
206
+ repo_info = get_repo_name_from_url(repo_url)
207
+ if not repo_info:
339
208
  print(f"❌ Invalid repository URL: {repo_url}")
340
209
  return None, None
341
- release_data = self._fetch_github_release_data(repo_name, version)
342
- if not release_data:
210
+ username, repository = repo_info
211
+ release_info = get_release_info(username, repository, version)
212
+ if not release_info:
343
213
  return None, None
344
- # print(release_data)
345
- actual_version = release_data.get("tag_name", "unknown")
214
+ actual_version = release_info.get("tag_name", "unknown") or "unknown"
346
215
  filename = filename_pattern.format(version=actual_version)
347
216
 
348
217
  available_filenames: list[str] = []
349
- for asset in release_data.get("assets", []):
350
- an_dl = asset.get("browser_download_url", "NA")
218
+ for asset in release_info["assets"]:
219
+ an_dl = asset["browser_download_url"]
351
220
  available_filenames.append(an_dl.split("/")[-1])
352
221
  if filename not in available_filenames:
353
- filename = filename_pattern.format(version=actual_version.replace("v", ""))
354
- if filename not in available_filenames:
355
- print(f"❌ Filename {filename} not found in assets: {available_filenames}")
222
+ candidates = [
223
+ filename,
224
+ filename_pattern.format(version=actual_version),
225
+ filename_pattern.format(version=actual_version.replace("v", "")),
226
+ ]
227
+
228
+ # Include hyphen/underscore variants
229
+ variants = []
230
+ for f in candidates:
231
+ variants += [f, f.replace("-", "_"), f.replace("_", "-")]
232
+
233
+ for f in variants:
234
+ if f in available_filenames:
235
+ filename = f
236
+ break
237
+ else:
238
+ print(f"❌ Filename not found in assets. Tried: {variants}\nAvailable: {available_filenames}")
356
239
  return None, None
357
240
  browser_download_url = f"{repo_url}/releases/download/{actual_version}/{filename}"
358
241
  return browser_download_url, actual_version