machineconfig 3.7__py3-none-any.whl → 7.69__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 (465) hide show
  1. machineconfig/__init__.py +0 -28
  2. machineconfig/cluster/remote/distribute.py +0 -1
  3. machineconfig/cluster/remote/file_manager.py +0 -2
  4. machineconfig/cluster/remote/script_execution.py +1 -2
  5. machineconfig/cluster/sessions_managers/{enhanced_command_runner.py → helpers/enhanced_command_runner.py} +4 -6
  6. machineconfig/cluster/sessions_managers/helpers/load_balancer_helper.py +145 -0
  7. machineconfig/cluster/sessions_managers/utils/load_balancer.py +53 -0
  8. machineconfig/cluster/sessions_managers/utils/maker.py +69 -0
  9. machineconfig/cluster/sessions_managers/wt_local.py +128 -330
  10. machineconfig/cluster/sessions_managers/wt_local_manager.py +53 -187
  11. machineconfig/cluster/sessions_managers/wt_remote.py +51 -43
  12. machineconfig/cluster/sessions_managers/wt_remote_manager.py +49 -197
  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 +22 -172
  21. machineconfig/cluster/sessions_managers/zellij_remote.py +40 -41
  22. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +13 -10
  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 +7 -21
  32. machineconfig/jobs/installer/custom/boxes.py +61 -0
  33. machineconfig/jobs/installer/custom/gh.py +128 -0
  34. machineconfig/jobs/{python_custom_installers → installer/custom}/hx.py +84 -18
  35. machineconfig/jobs/installer/custom_dev/alacritty.py +86 -0
  36. machineconfig/jobs/installer/custom_dev/brave.py +82 -0
  37. machineconfig/jobs/installer/custom_dev/bypass_paywall.py +59 -0
  38. machineconfig/jobs/installer/custom_dev/cloudflare_warp_cli.py +23 -0
  39. machineconfig/jobs/installer/custom_dev/code.py +63 -0
  40. machineconfig/jobs/{python_custom_installers/dev → installer/custom_dev}/cursor.py +7 -7
  41. machineconfig/jobs/installer/custom_dev/dubdb_adbc.py +30 -0
  42. machineconfig/jobs/installer/custom_dev/espanso.py +117 -0
  43. machineconfig/jobs/installer/custom_dev/goes.py +68 -0
  44. machineconfig/jobs/installer/custom_dev/lvim.py +89 -0
  45. machineconfig/jobs/installer/custom_dev/nerdfont.py +111 -0
  46. machineconfig/jobs/installer/custom_dev/nerfont_windows_helper.py +149 -0
  47. machineconfig/jobs/installer/custom_dev/redis.py +88 -0
  48. machineconfig/jobs/installer/custom_dev/sysabc.py +145 -0
  49. machineconfig/jobs/installer/custom_dev/wezterm.py +92 -0
  50. machineconfig/jobs/{python_custom_installers/dev → installer/custom_dev}/winget.py +2 -3
  51. machineconfig/jobs/installer/installer_data.json +3440 -0
  52. machineconfig/jobs/{python_custom_installers/scripts/linux → installer/linux_scripts}/brave.sh +4 -14
  53. machineconfig/jobs/{python_custom_installers/scripts/linux/warp-cli.sh → installer/linux_scripts/cloudflare_warp_cli.sh} +5 -17
  54. machineconfig/jobs/{python_custom_installers/scripts/linux → installer/linux_scripts}/docker.sh +6 -18
  55. machineconfig/jobs/installer/linux_scripts/docker_start.sh +37 -0
  56. machineconfig/jobs/{python_custom_installers/scripts/linux → installer/linux_scripts}/edge.sh +3 -11
  57. machineconfig/jobs/{linux/msc → installer/linux_scripts}/lid.sh +2 -8
  58. machineconfig/jobs/{python_custom_installers/scripts/linux → installer/linux_scripts}/nerdfont.sh +5 -17
  59. machineconfig/jobs/{linux/msc → installer/linux_scripts}/network.sh +2 -8
  60. machineconfig/jobs/installer/linux_scripts/ngrok.sh +6 -0
  61. machineconfig/jobs/installer/linux_scripts/q.sh +9 -0
  62. machineconfig/jobs/{python_custom_installers/scripts/linux → installer/linux_scripts}/redis.sh +6 -17
  63. machineconfig/jobs/{python_custom_installers/scripts/linux → installer/linux_scripts}/vscode.sh +5 -17
  64. machineconfig/jobs/{python_custom_installers/scripts/linux → installer/linux_scripts}/wezterm.sh +4 -12
  65. machineconfig/jobs/installer/package_groups.py +255 -0
  66. machineconfig/logger.py +0 -1
  67. machineconfig/profile/backup.toml +49 -0
  68. machineconfig/profile/bash_shell_profiles.md +11 -0
  69. machineconfig/profile/create_helper.py +74 -0
  70. machineconfig/profile/create_links.py +288 -0
  71. machineconfig/profile/create_links_export.py +100 -0
  72. machineconfig/profile/create_shell_profile.py +136 -0
  73. machineconfig/profile/mapper.toml +258 -0
  74. machineconfig/scripts/__init__.py +0 -4
  75. machineconfig/scripts/linux/{share_cloud.sh → other/share_cloud.sh} +14 -25
  76. machineconfig/scripts/linux/wrap_mcfg +47 -0
  77. machineconfig/scripts/nu/wrap_mcfg.nu +69 -0
  78. machineconfig/scripts/python/agents.py +198 -0
  79. machineconfig/scripts/python/ai/command_runner/command_runner.sh +9 -0
  80. machineconfig/scripts/python/ai/command_runner/prompt.txt +9 -0
  81. machineconfig/scripts/python/ai/generate_files.py +307 -42
  82. machineconfig/scripts/python/ai/{mcinit.py → initai.py} +3 -38
  83. machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +114 -0
  84. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +88 -22
  85. machineconfig/scripts/python/ai/solutions/_shared.py +9 -1
  86. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +4 -1
  87. machineconfig/scripts/python/ai/solutions/copilot/prompts/pyright_fix.md +16 -0
  88. machineconfig/scripts/python/ai/solutions/gemini/settings.json +1 -1
  89. machineconfig/scripts/python/ai/solutions/generic.py +27 -4
  90. machineconfig/scripts/python/ai/vscode_tasks.py +37 -0
  91. machineconfig/scripts/python/cloud.py +29 -0
  92. machineconfig/scripts/python/croshell.py +129 -198
  93. machineconfig/scripts/python/define.py +31 -0
  94. machineconfig/scripts/python/devops.py +45 -131
  95. machineconfig/scripts/python/devops_navigator.py +6 -0
  96. machineconfig/scripts/python/env_manager/__init__.py +1 -0
  97. machineconfig/scripts/python/env_manager/path_manager_backend.py +47 -0
  98. machineconfig/scripts/python/env_manager/path_manager_tui.py +228 -0
  99. machineconfig/scripts/python/fire_jobs.py +166 -235
  100. machineconfig/scripts/python/ftpx.py +164 -100
  101. machineconfig/scripts/python/helpers/ast_search.py +74 -0
  102. machineconfig/scripts/python/helpers/repo_rag.py +325 -0
  103. machineconfig/scripts/python/helpers/symantic_search.py +25 -0
  104. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.json +14 -0
  105. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.py +37 -0
  106. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_cursor_agents.py +22 -0
  107. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_gemini.py +42 -0
  108. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_qwen.py +30 -0
  109. machineconfig/scripts/python/helpers_agents/fire_agents_help_launch.py +110 -0
  110. machineconfig/scripts/python/helpers_agents/fire_agents_helper_types.py +34 -0
  111. machineconfig/scripts/python/helpers_agents/fire_agents_load_balancer.py +22 -0
  112. machineconfig/scripts/python/helpers_agents/templates/prompt.txt +6 -0
  113. machineconfig/scripts/python/helpers_agents/templates/template.ps1 +14 -0
  114. machineconfig/scripts/python/helpers_agents/templates/template.sh +24 -0
  115. machineconfig/scripts/python/{cloud_copy.py → helpers_cloud/cloud_copy.py} +52 -39
  116. machineconfig/scripts/python/{cloud_mount.py → helpers_cloud/cloud_mount.py} +13 -18
  117. machineconfig/scripts/python/helpers_cloud/cloud_sync.py +81 -0
  118. machineconfig/scripts/python/{helpers → helpers_cloud}/helpers2.py +3 -3
  119. machineconfig/scripts/python/helpers_croshell/crosh.py +39 -0
  120. machineconfig/scripts/python/{scheduler.py → helpers_croshell/scheduler.py} +0 -1
  121. machineconfig/scripts/python/{start_slidev.py → helpers_croshell/start_slidev.py} +32 -20
  122. machineconfig/scripts/python/helpers_devops/cli_config.py +95 -0
  123. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +89 -0
  124. machineconfig/scripts/python/helpers_devops/cli_data.py +25 -0
  125. machineconfig/scripts/python/helpers_devops/cli_nw.py +134 -0
  126. machineconfig/scripts/python/helpers_devops/cli_repos.py +182 -0
  127. machineconfig/scripts/python/helpers_devops/cli_self.py +134 -0
  128. machineconfig/scripts/python/helpers_devops/cli_share_file.py +137 -0
  129. machineconfig/scripts/python/helpers_devops/cli_share_server.py +141 -0
  130. machineconfig/scripts/python/helpers_devops/cli_terminal.py +156 -0
  131. machineconfig/scripts/python/helpers_devops/cli_utils.py +96 -0
  132. machineconfig/scripts/python/{devops_backup_retrieve.py → helpers_devops/devops_backup_retrieve.py} +7 -10
  133. machineconfig/scripts/python/helpers_devops/devops_status.py +511 -0
  134. machineconfig/scripts/python/helpers_devops/devops_update_repos.py +269 -0
  135. machineconfig/scripts/python/helpers_devops/themes/choose_pwsh_theme.ps1 +81 -0
  136. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +3 -0
  137. machineconfig/scripts/python/{choose_wezterm_theme.py → helpers_devops/themes/choose_wezterm_theme.py} +2 -2
  138. machineconfig/scripts/python/{cloud_manager.py → helpers_fire_command/cloud_manager.py} +0 -2
  139. machineconfig/scripts/python/{helpers/helpers4.py → helpers_fire_command/file_wrangler.py} +57 -89
  140. machineconfig/scripts/python/helpers_fire_command/fire_jobs_args_helper.py +145 -0
  141. machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +110 -0
  142. machineconfig/scripts/python/helpers_msearch/__init__.py +5 -0
  143. machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/fzfag +1 -1
  144. machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/fzfg +1 -1
  145. machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/fzfrga +1 -1
  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_repos/action.py +209 -0
  154. machineconfig/scripts/python/helpers_repos/action_helper.py +150 -0
  155. machineconfig/scripts/python/{repos_helper_clone.py → helpers_repos/clone.py} +6 -7
  156. machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +218 -0
  157. machineconfig/scripts/python/helpers_repos/count_lines.py +348 -0
  158. machineconfig/scripts/python/helpers_repos/count_lines_frontend.py +17 -0
  159. machineconfig/scripts/python/helpers_repos/entrypoint.py +77 -0
  160. machineconfig/scripts/python/helpers_repos/grource.py +340 -0
  161. machineconfig/scripts/python/{repos_helper_record.py → helpers_repos/record.py} +7 -4
  162. machineconfig/scripts/python/helpers_repos/sync.py +66 -0
  163. machineconfig/scripts/python/{repos_helper_update.py → helpers_repos/update.py} +3 -3
  164. machineconfig/scripts/python/helpers_sessions/sessions_multiprocess.py +58 -0
  165. machineconfig/scripts/python/helpers_utils/download.py +152 -0
  166. machineconfig/scripts/python/helpers_utils/path.py +108 -0
  167. machineconfig/scripts/python/interactive.py +187 -0
  168. machineconfig/scripts/python/mcfg_entry.py +63 -0
  169. machineconfig/scripts/python/msearch.py +40 -0
  170. machineconfig/scripts/python/{devops_add_identity.py → nw/devops_add_identity.py} +1 -3
  171. machineconfig/scripts/python/{devops_add_ssh_key.py → nw/devops_add_ssh_key.py} +74 -44
  172. machineconfig/scripts/{linux → python/nw}/mount_nfs +1 -1
  173. machineconfig/scripts/python/{mount_nfs.py → nw/mount_nfs.py} +19 -16
  174. machineconfig/scripts/{linux → python/nw}/mount_nw_drive +1 -2
  175. machineconfig/scripts/python/{mount_ssh.py → nw/mount_ssh.py} +7 -8
  176. machineconfig/scripts/python/{onetimeshare.py → nw/onetimeshare.py} +0 -1
  177. machineconfig/scripts/python/nw/ssh_debug_linux.py +391 -0
  178. machineconfig/scripts/python/nw/ssh_debug_windows.py +338 -0
  179. machineconfig/scripts/python/{wifi_conn.py → nw/wifi_conn.py} +1 -51
  180. machineconfig/scripts/python/nw/wsl_windows_transfer.py +67 -0
  181. machineconfig/scripts/python/sessions.py +167 -0
  182. machineconfig/scripts/python/terminal.py +127 -0
  183. machineconfig/scripts/python/utils.py +66 -0
  184. machineconfig/scripts/windows/mounts/Restore-ThunderbirdProfile.ps1 +92 -0
  185. machineconfig/scripts/windows/{mount_nfs.ps1 → mounts/mount_nfs.ps1} +1 -3
  186. machineconfig/scripts/windows/{mount_ssh.ps1 → mounts/mount_ssh.ps1} +1 -1
  187. machineconfig/scripts/windows/{share_smb.ps1 → mounts/share_smb.ps1} +0 -6
  188. machineconfig/scripts/windows/wrap_mcfg.ps1 +60 -0
  189. machineconfig/settings/broot/br.sh +0 -4
  190. machineconfig/settings/broot/conf.toml +1 -1
  191. machineconfig/settings/helix/config.toml +16 -0
  192. machineconfig/settings/helix/languages.toml +13 -4
  193. machineconfig/settings/helix/yazi-picker.sh +12 -0
  194. machineconfig/settings/lf/linux/exe/lfcd.sh +1 -0
  195. machineconfig/settings/lf/linux/exe/previewer.sh +9 -3
  196. machineconfig/settings/lf/linux/lfrc +10 -12
  197. machineconfig/settings/lf/windows/fzf_edit.ps1 +2 -2
  198. machineconfig/settings/lf/windows/lfcd.ps1 +1 -1
  199. machineconfig/settings/lf/windows/lfrc +18 -38
  200. machineconfig/settings/lf/windows/mkfile.ps1 +1 -1
  201. machineconfig/settings/linters/.ruff.toml +1 -1
  202. machineconfig/settings/lvim/windows/archive/config_additional.lua +0 -6
  203. machineconfig/settings/marimo/marimo.toml +80 -0
  204. machineconfig/settings/marimo/snippets/globalize.py +34 -0
  205. machineconfig/settings/pistol/pistol.conf +1 -1
  206. machineconfig/settings/shells/bash/init.sh +55 -31
  207. machineconfig/settings/shells/nushell/config.nu +1 -34
  208. machineconfig/settings/shells/nushell/init.nu +127 -0
  209. machineconfig/settings/shells/pwsh/init.ps1 +61 -43
  210. machineconfig/settings/shells/starship/starship.toml +16 -0
  211. machineconfig/settings/shells/wezterm/wezterm.lua +2 -0
  212. machineconfig/settings/shells/wt/settings.json +32 -17
  213. machineconfig/settings/shells/zsh/init.sh +89 -0
  214. machineconfig/settings/svim/linux/init.toml +0 -4
  215. machineconfig/settings/svim/windows/init.toml +0 -3
  216. machineconfig/settings/yazi/init.lua +57 -0
  217. machineconfig/settings/yazi/keymap_linux.toml +79 -0
  218. machineconfig/settings/yazi/keymap_windows.toml +78 -0
  219. machineconfig/settings/yazi/shell/yazi_cd.ps1 +33 -0
  220. machineconfig/settings/yazi/shell/yazi_cd.sh +8 -0
  221. machineconfig/settings/yazi/yazi.toml +14 -1
  222. machineconfig/setup_linux/__init__.py +10 -0
  223. machineconfig/setup_linux/apps_desktop.sh +89 -0
  224. machineconfig/setup_linux/apps_gui.sh +64 -0
  225. machineconfig/setup_linux/{nix → others}/cli_installation.sh +9 -29
  226. machineconfig/setup_linux/ssh/openssh_all.sh +25 -0
  227. machineconfig/setup_linux/ssh/openssh_wsl.sh +38 -0
  228. machineconfig/setup_linux/uv.sh +15 -0
  229. machineconfig/setup_linux/web_shortcuts/interactive.sh +28 -203
  230. machineconfig/setup_mac/__init__.py +16 -0
  231. machineconfig/setup_mac/apps_gui.sh +248 -0
  232. machineconfig/setup_mac/ssh/openssh_setup.sh +114 -0
  233. machineconfig/setup_mac/uv.sh +36 -0
  234. machineconfig/setup_windows/__init__.py +8 -0
  235. machineconfig/setup_windows/others/power_options.ps1 +7 -0
  236. machineconfig/setup_windows/ssh/add-sshkey.ps1 +29 -0
  237. machineconfig/setup_windows/ssh/add_identity.ps1 +11 -0
  238. machineconfig/setup_windows/ssh/openssh-server.ps1 +37 -0
  239. machineconfig/setup_windows/uv.ps1 +17 -0
  240. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +28 -189
  241. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +17 -0
  242. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +37 -23
  243. machineconfig/utils/accessories.py +52 -12
  244. machineconfig/utils/cloud/onedrive/README.md +139 -0
  245. machineconfig/utils/code.py +140 -93
  246. machineconfig/utils/files/art/fat_croco.txt +10 -0
  247. machineconfig/utils/files/art/halfwit_croco.txt +9 -0
  248. machineconfig/utils/files/art/happy_croco.txt +22 -0
  249. machineconfig/utils/files/art/water_croco.txt +11 -0
  250. machineconfig/utils/files/ascii_art.py +118 -0
  251. machineconfig/utils/files/dbms.py +257 -0
  252. machineconfig/utils/files/headers.py +68 -0
  253. machineconfig/utils/files/ouch/decompress.py +45 -0
  254. machineconfig/utils/files/read.py +95 -0
  255. machineconfig/utils/installer_utils/github_release_bulk.py +188 -0
  256. machineconfig/utils/installer_utils/install_from_url.py +180 -0
  257. machineconfig/utils/installer_utils/installer_class.py +239 -316
  258. machineconfig/utils/installer_utils/installer_cli.py +186 -0
  259. machineconfig/utils/installer_utils/{installer_abc.py → installer_locator_utils.py} +90 -5
  260. machineconfig/utils/installer_utils/installer_runner.py +191 -0
  261. machineconfig/utils/io.py +77 -24
  262. machineconfig/utils/links.py +309 -100
  263. machineconfig/utils/meta.py +255 -0
  264. machineconfig/utils/notifications.py +1 -1
  265. machineconfig/utils/options.py +19 -47
  266. machineconfig/utils/path_extended.py +111 -121
  267. machineconfig/utils/path_helper.py +75 -22
  268. machineconfig/utils/procs.py +50 -74
  269. machineconfig/utils/scheduler.py +94 -97
  270. machineconfig/utils/scheduling.py +0 -3
  271. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +5 -17
  272. machineconfig/utils/schemas/installer/installer_types.py +28 -6
  273. machineconfig/utils/schemas/layouts/layout_types.py +34 -1
  274. machineconfig/utils/source_of_truth.py +3 -6
  275. machineconfig/utils/ssh.py +742 -254
  276. machineconfig/utils/ssh_utils/utils.py +0 -0
  277. machineconfig/utils/terminal.py +3 -140
  278. machineconfig/utils/tst.py +20 -0
  279. machineconfig/utils/upgrade_packages.py +109 -28
  280. machineconfig/utils/ve.py +13 -5
  281. machineconfig-7.69.dist-info/METADATA +124 -0
  282. machineconfig-7.69.dist-info/RECORD +454 -0
  283. machineconfig-7.69.dist-info/entry_points.txt +15 -0
  284. machineconfig/cluster/templates/cli_click.py +0 -102
  285. machineconfig/cluster/templates/cli_gooey.py +0 -115
  286. machineconfig/cluster/templates/utils.py +0 -51
  287. machineconfig/jobs/linux/msc/cli_agents.sh +0 -32
  288. machineconfig/jobs/python/create_bootable_media.py +0 -16
  289. machineconfig/jobs/python/python_cargo_build_share.py +0 -59
  290. machineconfig/jobs/python/python_ve_symlink.py +0 -29
  291. machineconfig/jobs/python/tasks.py +0 -3
  292. machineconfig/jobs/python/vscode/api.py +0 -48
  293. machineconfig/jobs/python/vscode/link_ve.py +0 -63
  294. machineconfig/jobs/python/vscode/select_interpreter.py +0 -87
  295. machineconfig/jobs/python/vscode/sync_code.py +0 -58
  296. machineconfig/jobs/python_custom_installers/archive/ngrok.py +0 -63
  297. machineconfig/jobs/python_custom_installers/dev/aider.py +0 -37
  298. machineconfig/jobs/python_custom_installers/dev/alacritty.py +0 -65
  299. machineconfig/jobs/python_custom_installers/dev/brave.py +0 -71
  300. machineconfig/jobs/python_custom_installers/dev/bypass_paywall.py +0 -50
  301. machineconfig/jobs/python_custom_installers/dev/code.py +0 -51
  302. machineconfig/jobs/python_custom_installers/dev/docker_desktop.py +0 -78
  303. machineconfig/jobs/python_custom_installers/dev/espanso.py +0 -90
  304. machineconfig/jobs/python_custom_installers/dev/goes.py +0 -55
  305. machineconfig/jobs/python_custom_installers/dev/lvim.py +0 -77
  306. machineconfig/jobs/python_custom_installers/dev/nerdfont.py +0 -68
  307. machineconfig/jobs/python_custom_installers/dev/redis.py +0 -65
  308. machineconfig/jobs/python_custom_installers/dev/reverse_proxy.md +0 -31
  309. machineconfig/jobs/python_custom_installers/dev/wezterm.py +0 -70
  310. machineconfig/jobs/python_custom_installers/docker.py +0 -74
  311. machineconfig/jobs/python_custom_installers/gh.py +0 -97
  312. machineconfig/jobs/python_custom_installers/scripts/linux/docker_start.sh +0 -45
  313. machineconfig/jobs/python_custom_installers/scripts/linux/pgsql.sh +0 -49
  314. machineconfig/jobs/python_custom_installers/scripts/linux/timescaledb.sh +0 -85
  315. machineconfig/jobs/python_custom_installers/warp-cli.py +0 -71
  316. machineconfig/jobs/python_generic_installers/config.json +0 -603
  317. machineconfig/jobs/python_generic_installers/config.json.bak +0 -414
  318. machineconfig/jobs/python_generic_installers/dev/config.archive.json +0 -18
  319. machineconfig/jobs/python_generic_installers/dev/config.json +0 -825
  320. machineconfig/jobs/python_generic_installers/dev/config.json.bak +0 -565
  321. machineconfig/jobs/python_linux_installers/archive/config.json +0 -18
  322. machineconfig/jobs/python_linux_installers/archive/config.json.bak +0 -10
  323. machineconfig/jobs/python_linux_installers/config.json +0 -145
  324. machineconfig/jobs/python_linux_installers/config.json.bak +0 -110
  325. machineconfig/jobs/python_linux_installers/dev/config.json +0 -276
  326. machineconfig/jobs/python_linux_installers/dev/config.json.bak +0 -206
  327. machineconfig/jobs/python_windows_installers/archive/file.json +0 -11
  328. machineconfig/jobs/python_windows_installers/config.json +0 -82
  329. machineconfig/jobs/python_windows_installers/config.json.bak +0 -56
  330. machineconfig/jobs/python_windows_installers/dev/config.json +0 -4
  331. machineconfig/jobs/python_windows_installers/dev/config.json.bak +0 -3
  332. machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +0 -14
  333. machineconfig/jobs/windows/start_terminal.ps1 +0 -6
  334. machineconfig/jobs/windows/startup_file.cmd +0 -2
  335. machineconfig/profile/create.py +0 -169
  336. machineconfig/profile/shell.py +0 -176
  337. machineconfig/scripts/cloud/init.sh +0 -119
  338. machineconfig/scripts/linux/choose_wezterm_theme +0 -3
  339. machineconfig/scripts/linux/cloud_copy +0 -2
  340. machineconfig/scripts/linux/cloud_mount +0 -2
  341. machineconfig/scripts/linux/cloud_repo_sync +0 -2
  342. machineconfig/scripts/linux/cloud_sync +0 -2
  343. machineconfig/scripts/linux/croshell +0 -3
  344. machineconfig/scripts/linux/devops +0 -2
  345. machineconfig/scripts/linux/fire +0 -2
  346. machineconfig/scripts/linux/fire_agents +0 -2
  347. machineconfig/scripts/linux/ftpx +0 -2
  348. machineconfig/scripts/linux/fzf2g +0 -21
  349. machineconfig/scripts/linux/fzffg +0 -25
  350. machineconfig/scripts/linux/gh_models +0 -2
  351. machineconfig/scripts/linux/kill_process +0 -2
  352. machineconfig/scripts/linux/mcinit +0 -2
  353. machineconfig/scripts/linux/programs +0 -21
  354. machineconfig/scripts/linux/repos +0 -2
  355. machineconfig/scripts/linux/scheduler +0 -2
  356. machineconfig/scripts/linux/share_smb +0 -1
  357. machineconfig/scripts/linux/start_slidev +0 -2
  358. machineconfig/scripts/linux/start_terminals +0 -3
  359. machineconfig/scripts/linux/warp-cli.sh +0 -122
  360. machineconfig/scripts/linux/wifi_conn +0 -2
  361. machineconfig/scripts/linux/z_ls +0 -104
  362. machineconfig/scripts/python/ai/solutions/copilot/prompts/allLintersAndTypeCheckers.prompt.md +0 -5
  363. machineconfig/scripts/python/archive/im2text.py +0 -34
  364. machineconfig/scripts/python/archive/tmate_conn.py +0 -41
  365. machineconfig/scripts/python/archive/tmate_start.py +0 -44
  366. machineconfig/scripts/python/cloud_repo_sync.py +0 -192
  367. machineconfig/scripts/python/cloud_sync.py +0 -85
  368. machineconfig/scripts/python/devops_devapps_install.py +0 -202
  369. machineconfig/scripts/python/devops_update_repos.py +0 -180
  370. machineconfig/scripts/python/dotfile.py +0 -52
  371. machineconfig/scripts/python/fire_agents.py +0 -176
  372. machineconfig/scripts/python/fire_agents_help_launch.py +0 -143
  373. machineconfig/scripts/python/fire_agents_load_balancer.py +0 -50
  374. machineconfig/scripts/python/fire_jobs_args_helper.py +0 -84
  375. machineconfig/scripts/python/fire_jobs_layout_helper.py +0 -66
  376. machineconfig/scripts/python/get_zellij_cmd.py +0 -15
  377. machineconfig/scripts/python/gh_models.py +0 -104
  378. machineconfig/scripts/python/helpers/repo_sync_helpers.py +0 -114
  379. machineconfig/scripts/python/repos.py +0 -160
  380. machineconfig/scripts/python/snapshot.py +0 -25
  381. machineconfig/scripts/python/start_terminals.py +0 -121
  382. machineconfig/scripts/python/wsl_windows_transfer.py +0 -72
  383. machineconfig/scripts/windows/choose_wezterm_theme.ps1 +0 -1
  384. machineconfig/scripts/windows/cloud_copy.ps1 +0 -1
  385. machineconfig/scripts/windows/cloud_mount.ps1 +0 -1
  386. machineconfig/scripts/windows/cloud_repo_sync.ps1 +0 -1
  387. machineconfig/scripts/windows/cloud_sync.ps1 +0 -1
  388. machineconfig/scripts/windows/croshell.ps1 +0 -1
  389. machineconfig/scripts/windows/devops.ps1 +0 -1
  390. machineconfig/scripts/windows/dotfile.ps1 +0 -1
  391. machineconfig/scripts/windows/fire.ps1 +0 -1
  392. machineconfig/scripts/windows/ftpx.ps1 +0 -1
  393. machineconfig/scripts/windows/gpt.ps1 +0 -1
  394. machineconfig/scripts/windows/grep.ps1 +0 -2
  395. machineconfig/scripts/windows/kill_process.ps1 +0 -1
  396. machineconfig/scripts/windows/mcinit.ps1 +0 -1
  397. machineconfig/scripts/windows/nano.ps1 +0 -3
  398. machineconfig/scripts/windows/pomodoro.ps1 +0 -1
  399. machineconfig/scripts/windows/reload_path.ps1 +0 -3
  400. machineconfig/scripts/windows/repos.ps1 +0 -1
  401. machineconfig/scripts/windows/scheduler.ps1 +0 -1
  402. machineconfig/scripts/windows/snapshot.ps1 +0 -1
  403. machineconfig/scripts/windows/start_slidev.ps1 +0 -1
  404. machineconfig/scripts/windows/start_terminals.ps1 +0 -1
  405. machineconfig/scripts/windows/wifi_conn.ps1 +0 -2
  406. machineconfig/scripts/windows/wsl_rdp_windows_port_forwarding.ps1 +0 -46
  407. machineconfig/scripts/windows/wsl_ssh_windows_port_forwarding.ps1 +0 -76
  408. machineconfig/settings/lf/linux/exe/fzf_nano.sh +0 -16
  409. machineconfig/setup_linux/others/openssh-server_add_pub_key.sh +0 -57
  410. machineconfig/setup_linux/web_shortcuts/ascii_art.sh +0 -93
  411. machineconfig/setup_linux/web_shortcuts/croshell.sh +0 -11
  412. machineconfig/setup_linux/web_shortcuts/ssh.sh +0 -52
  413. machineconfig/setup_windows/web_shortcuts/all.ps1 +0 -18
  414. machineconfig/setup_windows/web_shortcuts/ascii_art.ps1 +0 -36
  415. machineconfig/setup_windows/web_shortcuts/croshell.ps1 +0 -16
  416. machineconfig/setup_windows/web_shortcuts/ssh.ps1 +0 -11
  417. machineconfig/setup_windows/wt_and_pwsh/install_nerd_fonts.py +0 -100
  418. machineconfig/utils/ai/generate_file_checklist.py +0 -68
  419. machineconfig/utils/installer.py +0 -255
  420. machineconfig-3.7.dist-info/METADATA +0 -165
  421. machineconfig-3.7.dist-info/RECORD +0 -432
  422. machineconfig-3.7.dist-info/entry_points.txt +0 -18
  423. machineconfig/cluster/{templates → remote}/run_cloud.py +0 -0
  424. machineconfig/cluster/{templates → remote}/run_cluster.py +0 -0
  425. machineconfig/cluster/{templates → remote}/run_remote.py +0 -0
  426. machineconfig/jobs/{python → installer}/__init__.py +0 -0
  427. machineconfig/jobs/{python_custom_installers → installer/custom_dev}/__init__.py +0 -0
  428. machineconfig/{setup_windows/wt_and_pwsh → jobs/installer/powershell_scripts}/install_fonts.ps1 +0 -0
  429. machineconfig/scripts/linux/{share_nfs → other/share_nfs} +0 -0
  430. machineconfig/scripts/linux/{start_docker → other/start_docker} +0 -0
  431. machineconfig/scripts/linux/{switch_ip → other/switch_ip} +0 -0
  432. machineconfig/{jobs/python_generic_installers → scripts/python/helpers_agents}/__init__.py +0 -0
  433. machineconfig/{jobs/python_linux_installers → scripts/python/helpers_agents/agentic_frameworks}/__init__.py +0 -0
  434. machineconfig/scripts/python/{fire_agents_help_search.py → helpers_agents/fire_agents_help_search.py} +0 -0
  435. machineconfig/{jobs/python_linux_installers/dev → scripts/python/helpers_cloud}/__init__.py +0 -0
  436. machineconfig/scripts/python/{helpers → helpers_cloud}/cloud_helpers.py +1 -1
  437. /machineconfig/scripts/python/{helpers → helpers_cloud}/helpers5.py +0 -0
  438. /machineconfig/{jobs/python_windows_installers → scripts/python/helpers_croshell}/__init__.py +0 -0
  439. /machineconfig/scripts/python/{pomodoro.py → helpers_croshell/pomodoro.py} +0 -0
  440. /machineconfig/scripts/python/{viewer.py → helpers_croshell/viewer.py} +0 -0
  441. /machineconfig/scripts/python/{viewer_template.py → helpers_croshell/viewer_template.py} +0 -0
  442. /machineconfig/{jobs/python_windows_installers/archive → scripts/python/helpers_devops}/__init__.py +0 -0
  443. /machineconfig/{jobs/python_windows_installers/dev → scripts/python/helpers_devops/themes}/__init__.py +0 -0
  444. /machineconfig/{jobs/windows/msc/cli_agents.bat → scripts/python/helpers_devops/themes/choose_starship_theme.ps1} +0 -0
  445. /machineconfig/scripts/python/{helpers → helpers_fire_command}/__init__.py +0 -0
  446. /machineconfig/scripts/python/{fire_jobs_streamlit_helper.py → helpers_fire_command/fire_jobs_streamlit_helper.py} +0 -0
  447. /machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/skrg +0 -0
  448. /machineconfig/scripts/{windows → python/helpers_msearch/scripts_windows}/fzfb.ps1 +0 -0
  449. /machineconfig/scripts/{windows → python/helpers_msearch/scripts_windows}/fzfg.ps1 +0 -0
  450. /machineconfig/scripts/{windows → python/helpers_msearch/scripts_windows}/fzfrga.bat +0 -0
  451. /machineconfig/{jobs/windows/msc/cli_agents.ps1 → scripts/python/helpers_sessions/__init__.py} +0 -0
  452. /machineconfig/scripts/{windows/share_nfs.ps1 → python/nw/__init__.py} +0 -0
  453. /machineconfig/scripts/{linux → python/nw}/mount_drive +0 -0
  454. /machineconfig/scripts/python/{mount_nw_drive.py → nw/mount_nw_drive.py} +0 -0
  455. /machineconfig/scripts/{linux → python/nw}/mount_smb +0 -0
  456. /machineconfig/scripts/windows/{mount_nw.ps1 → mounts/mount_nw.ps1} +0 -0
  457. /machineconfig/scripts/windows/{mount_smb.ps1 → mounts/mount_smb.ps1} +0 -0
  458. /machineconfig/scripts/windows/{share_cloud.cmd → mounts/share_cloud.cmd} +0 -0
  459. /machineconfig/scripts/windows/{unlock_bitlocker.ps1 → mounts/unlock_bitlocker.ps1} +0 -0
  460. /machineconfig/setup_linux/{web_shortcuts → others}/android.sh +0 -0
  461. /machineconfig/{jobs/windows/archive → setup_windows/ssh}/openssh-server_add_key.ps1 +0 -0
  462. /machineconfig/{jobs/windows/archive → setup_windows/ssh}/openssh-server_copy-ssh-id.ps1 +0 -0
  463. /machineconfig/{settings/yazi/keymap.toml → utils/files/ouch/__init__.py} +0 -0
  464. {machineconfig-3.7.dist-info → machineconfig-7.69.dist-info}/WHEEL +0 -0
  465. {machineconfig-3.7.dist-info → machineconfig-7.69.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,186 @@
1
+ """Devops Devapps Install"""
2
+
3
+ import typer
4
+ from typing import Annotated, Optional
5
+ from machineconfig.jobs.installer.package_groups import PACKAGE_GROUP2NAMES
6
+ from machineconfig.utils.installer_utils.installer_class import Installer
7
+
8
+
9
+
10
+ def main_installer_cli(
11
+ which: Annotated[Optional[str], typer.Argument(..., help="Comma-separated list of program/groups names to install (if --group flag is set).")] = None,
12
+ group: Annotated[bool, typer.Option(..., "--group", "-g", help="Treat 'which' as a group name. A group is bundle of apps.")] = False,
13
+ interactive: Annotated[bool, typer.Option(..., "--interactive", "-i", help="Interactive selection of programs to install.")] = False,
14
+ ) -> None:
15
+ if interactive:
16
+ return install_interactively()
17
+ if which is not None:
18
+ if group:
19
+ for a_group in [x.strip() for x in which.split(",") if x.strip() != ""]:
20
+ return install_group(package_group=a_group)
21
+ else:
22
+ return install_clis(clis_names=[x.strip() for x in which.split(",") if x.strip() != ""])
23
+ else:
24
+ if group:
25
+ from rich.console import Console
26
+ from rich.table import Table
27
+ console = Console()
28
+
29
+ typer.echo("❌ You must provide a group name when using the --group/-g option.")
30
+ res = get_group_name_to_repr()
31
+ console.print("[bold blue]Here are the available groups:[/bold blue]")
32
+ table = Table(show_header=True, header_style="bold magenta")
33
+ table.add_column("Group", style="cyan", no_wrap=True)
34
+ table.add_column("AppsBundled", style="green", overflow="fold")
35
+ for display, group_name in res.items():
36
+ # Parse display
37
+ if " -- " in display:
38
+ group_part, items_part = display.split(" -- ", 1)
39
+ group_name_parsed = group_part.replace("📦 ", "").strip()
40
+ items_str = items_part.strip()
41
+ else:
42
+ group_name_parsed = display
43
+ items_str = group_name
44
+ table.add_row(group_name_parsed, items_str)
45
+ console.print(table)
46
+ raise typer.Exit(1)
47
+ typer.echo("❌ You must provide either a program name/group name, or use --interactive/-ia option.")
48
+ import click
49
+ ctx = click.get_current_context()
50
+ typer.echo(ctx.get_help())
51
+ raise typer.Exit(1)
52
+
53
+
54
+ def get_group_name_to_repr() -> dict[str, str]:
55
+ # Build category options and maintain a mapping from display text to actual category name
56
+ category_display_to_name: dict[str, str] = {}
57
+ for group_name, group_values in PACKAGE_GROUP2NAMES.items():
58
+ display = f"📦 {group_name:<20}" + " -- " + f"{'|'.join(group_values):<60}"
59
+ category_display_to_name[display] = group_name
60
+ return category_display_to_name
61
+
62
+
63
+ def install_interactively():
64
+ from machineconfig.utils.options import choose_from_options
65
+ from machineconfig.utils.schemas.installer.installer_types import get_normalized_arch, get_os_name
66
+ from machineconfig.utils.installer_utils.installer_runner import get_installers
67
+ from machineconfig.utils.installer_utils.installer_class import Installer
68
+ from rich.console import Console
69
+ from rich.panel import Panel
70
+ # from rich.table import Table
71
+ installers = get_installers(os=get_os_name(), arch=get_normalized_arch(), which_cats=None)
72
+ installer_options = [Installer(installer_data=x).get_description() for x in installers]
73
+ category_display_to_name = get_group_name_to_repr()
74
+ options = list(category_display_to_name.keys()) + installer_options
75
+ program_names = choose_from_options(multi=True, msg="Categories are prefixed with 📦", options=options, header="🚀 CHOOSE DEV APP OR CATEGORY", fzf=True)
76
+ installation_messages: list[str] = []
77
+ for _an_idx, a_program_name in enumerate(program_names):
78
+ if a_program_name.startswith("📦 "):
79
+ category_name = category_display_to_name.get(a_program_name)
80
+ if category_name:
81
+ install_group(package_group=category_name)
82
+ else:
83
+ installer_idx = installer_options.index(a_program_name)
84
+ an_installer_data = installers[installer_idx]
85
+ status_message = Installer(an_installer_data).install_robust(version=None) # finish the task - this returns a status message, not a command
86
+ installation_messages.append(status_message)
87
+ if installation_messages:
88
+ console = Console()
89
+
90
+ panel = Panel("\n".join([f"[blue]• {message}[/blue]" for message in installation_messages]), title="[bold green]📊 Installation Summary[/bold green]", border_style="green", padding=(1, 2))
91
+ console.print(panel)
92
+
93
+
94
+ def install_group(package_group: str):
95
+ from machineconfig.utils.installer_utils.installer_runner import get_installers, install_bulk
96
+ from machineconfig.utils.schemas.installer.installer_types import get_normalized_arch, get_os_name
97
+ from rich.console import Console
98
+ from rich.panel import Panel
99
+ # from rich.table import Table
100
+ if package_group in PACKAGE_GROUP2NAMES:
101
+ panel = Panel(f"[bold yellow]Installing programs from category: [green]{package_group}[/green][/bold yellow]", title="[bold blue]📦 Category Installation[/bold blue]", border_style="blue", padding=(1, 2))
102
+ console = Console()
103
+ console.print(panel)
104
+ installers_ = get_installers(os=get_os_name(), arch=get_normalized_arch(), which_cats=[package_group])
105
+ install_bulk(installers_data=installers_)
106
+ return
107
+ console = Console()
108
+ console.print(f"❌ ERROR: Unknown package group: {package_group}. Available groups are: {list(PACKAGE_GROUP2NAMES.keys())}")
109
+ def _handle_installer_not_found(search_term: str, all_names: list[str]) -> None: # type: ignore
110
+ """Handle installer not found with friendly suggestions using fuzzy matching."""
111
+ from difflib import get_close_matches
112
+ from rich.console import Console
113
+ from rich.panel import Panel
114
+ from rich.table import Table
115
+ close_matches = get_close_matches(search_term, all_names, n=5, cutoff=0.4)
116
+ console = Console()
117
+
118
+ console.print(f"\n❌ '[red]{search_term}[/red]' was not found.", style="bold")
119
+ if close_matches:
120
+ console.print("🤔 Did you mean one of these?", style="yellow")
121
+ table = Table(show_header=False, box=None, pad_edge=False)
122
+ for i, match in enumerate(close_matches, 1):
123
+ table.add_row(f"[cyan]{i}.[/cyan]", f"[green]{match}[/green]")
124
+ console.print(table)
125
+ else:
126
+ console.print("📋 Here are some available options:", style="blue")
127
+ # Show first 10 installers as examples
128
+ if len(all_names) > 10:
129
+ sample_names = all_names[:10]
130
+ else:
131
+ sample_names = all_names
132
+ table = Table(show_header=False, box=None, pad_edge=False)
133
+ for i, name in enumerate(sample_names, 1):
134
+ table.add_row(f"[cyan]{i}.[/cyan]", f"[green]{name}[/green]")
135
+ console.print(table)
136
+ if len(all_names) > 10:
137
+ console.print(f" [dim]... and {len(all_names) - 10} more[/dim]")
138
+
139
+ panel = Panel(f"[bold blue]💡 Use 'ia' to interactively browse all available installers.[/bold blue]\n[bold blue]💡 Use one of the categories: {list(PACKAGE_GROUP2NAMES.keys())}[/bold blue]", title="[yellow]Helpful Tips[/yellow]", border_style="yellow")
140
+ console.print(panel)
141
+
142
+ def install_clis(clis_names: list[str]):
143
+ from machineconfig.utils.schemas.installer.installer_types import get_normalized_arch, get_os_name
144
+ from machineconfig.utils.installer_utils.installer_runner import get_installers
145
+ from machineconfig.utils.installer_utils.installer_class import Installer
146
+ from rich.console import Console
147
+ all_installers = get_installers(os=get_os_name(), arch=get_normalized_arch(), which_cats=None)
148
+ total_messages: list[str] = []
149
+ for a_cli_name in clis_names:
150
+ if "github.com" in a_cli_name.lower():
151
+ from machineconfig.utils.installer_utils.install_from_url import install_from_github_url
152
+ install_from_github_url(github_url=a_cli_name)
153
+ continue
154
+ selected_installer = None
155
+ for installer in all_installers:
156
+ app_name = installer["appName"]
157
+ if app_name.lower() == a_cli_name.lower():
158
+ selected_installer = installer
159
+ break
160
+ if selected_installer is None:
161
+ _handle_installer_not_found(a_cli_name, all_names=[inst["appName"] for inst in all_installers])
162
+ return None
163
+ message = Installer(selected_installer).install_robust(version=None) # finish the task
164
+ total_messages.append(message)
165
+ if total_messages:
166
+ console = Console()
167
+ console.print("\n[bold green]📊 Installation Results:[/bold green]")
168
+ for a_message in total_messages:
169
+ console.print(f"[blue]• {a_message}[/blue]")
170
+ return None
171
+ def install_if_missing(which: str):
172
+ from machineconfig.utils.installer_utils.installer_locator_utils import check_tool_exists
173
+ exists = check_tool_exists(which)
174
+ if exists:
175
+ print(f"✅ {which} is already installed.")
176
+ return
177
+ print(f"⏳ {which} not found. Installing...")
178
+ from machineconfig.utils.installer_utils.installer_cli import main_installer_cli
179
+ main_installer_cli(which=which, interactive=False)
180
+
181
+
182
+ if __name__ == "__main__":
183
+ from machineconfig.utils.schemas.installer.installer_types import InstallerData
184
+ from machineconfig.utils.installer_utils.installer_class import Installer
185
+ _ = InstallerData, Installer
186
+ pass
@@ -1,11 +1,14 @@
1
- from machineconfig.utils.path_extended import PathExtended as PathExtended
2
- from machineconfig.utils.source_of_truth import WINDOWS_INSTALL_PATH, LINUX_INSTALL_PATH
1
+ from machineconfig.utils.path_extended import PathExtended
2
+ from machineconfig.utils.source_of_truth import WINDOWS_INSTALL_PATH, LINUX_INSTALL_PATH, INSTALL_VERSION_ROOT
3
+
4
+ from pathlib import Path
3
5
  from typing import Optional
4
6
  import subprocess
7
+ import platform
5
8
 
6
9
 
7
10
  def find_move_delete_windows(downloaded_file_path: PathExtended, exe_name: Optional[str] = None, delete: bool = True, rename_to: Optional[str] = None):
8
- print(f"\n{'=' * 80}\n🔍 PROCESSING WINDOWS EXECUTABLE 🔍\n{'=' * 80}")
11
+ print("🔍 PROCESSING WINDOWS EXECUTABLE 🔍")
9
12
  if exe_name is not None and ".exe" in exe_name:
10
13
  exe_name = exe_name.replace(".exe", "")
11
14
  if downloaded_file_path.is_file():
@@ -50,7 +53,7 @@ def find_move_delete_windows(downloaded_file_path: PathExtended, exe_name: Optio
50
53
 
51
54
 
52
55
  def find_move_delete_linux(downloaded: PathExtended, tool_name: str, delete: Optional[bool] = True, rename_to: Optional[str] = None):
53
- print(f"\n{'=' * 80}\n🔍 PROCESSING LINUX EXECUTABLE 🔍\n{'=' * 80}")
56
+ print("🔍 PROCESSING LINUX EXECUTABLE 🔍")
54
57
  if downloaded.is_file():
55
58
  exe = downloaded
56
59
  print(f"📄 Found direct executable file: {exe}")
@@ -104,5 +107,87 @@ def find_move_delete_linux(downloaded: PathExtended, tool_name: str, delete: Opt
104
107
  print("✅ Temporary files removed")
105
108
 
106
109
  exe_new_location = PathExtended(LINUX_INSTALL_PATH).joinpath(exe.name)
107
- print(f"✅ Executable installed at: {exe_new_location}\n{'=' * 80}")
110
+ print(f"✅ Executable installed at: {exe_new_location}")
108
111
  return exe_new_location
112
+
113
+
114
+ def check_tool_exists(tool_name: str) -> bool:
115
+ if platform.system() == "Windows":
116
+ tool_name_exe = tool_name.replace(".exe", "") + ".exe"
117
+ res1 = any([Path(WINDOWS_INSTALL_PATH).joinpath(tool_name_exe).is_file(), Path.home().joinpath("AppData/Roaming/npm").joinpath(tool_name_exe).is_file()])
118
+ if res1:
119
+ return True
120
+ tool_name_no_exe = tool_name.replace(".exe", "")
121
+ res2 = any([Path(WINDOWS_INSTALL_PATH).joinpath(tool_name_no_exe).is_file(), Path.home().joinpath("AppData/Roaming/npm").joinpath(tool_name_no_exe).is_file()])
122
+ return res2
123
+ elif platform.system() in ["Linux", "Darwin"]:
124
+ root_path = Path(LINUX_INSTALL_PATH)
125
+ standard_checks = [
126
+ Path("/usr/local/bin").joinpath(tool_name).is_file(),
127
+ Path("/usr/bin").joinpath(tool_name).is_file(),
128
+ root_path.joinpath(tool_name).is_file()
129
+ ]
130
+ if any(standard_checks):
131
+ return True
132
+ # Check for npm packages via nvm
133
+ npm_check = False
134
+ try:
135
+ result = subprocess.run(["node", "--version"], capture_output=True, text=True, check=True)
136
+ version = result.stdout.strip().lstrip('v')
137
+ nvm_bin_path = Path.home() / ".nvm" / "versions" / "node" / f"v{version}" / "bin" / tool_name
138
+ npm_check = nvm_bin_path.is_file()
139
+ except subprocess.CalledProcessError:
140
+ pass
141
+ return npm_check
142
+ else:
143
+ raise NotImplementedError(f"platform {platform.system()} not implemented")
144
+
145
+ def is_executable_in_path(name: str) -> bool:
146
+ import os
147
+ path_dirs = os.environ['PATH'].split(os.pathsep)
148
+ for path_dir in path_dirs:
149
+ path_to_executable = os.path.join(path_dir, name)
150
+ if os.path.isfile(path_to_executable) and os.access(path_to_executable, os.X_OK): return True
151
+ return False
152
+
153
+
154
+ def check_if_installed_already(exe_name: str, version: Optional[str], use_cache: bool) -> tuple[str, str, str]:
155
+ print(f"🔍 CHECKING INSTALLATION STATUS: {exe_name} 🔍")
156
+ INSTALL_VERSION_ROOT.joinpath(exe_name).parent.mkdir(parents=True, exist_ok=True)
157
+ tmp_path = INSTALL_VERSION_ROOT.joinpath(exe_name)
158
+
159
+ if use_cache:
160
+ print("🗂️ Using cached version information...")
161
+ if tmp_path.exists():
162
+ existing_version = tmp_path.read_text(encoding="utf-8").rstrip()
163
+ print(f"📄 Found cached version: {existing_version}")
164
+ else:
165
+ existing_version = None
166
+ print("ℹ️ No cached version information found")
167
+ else:
168
+ print("🔍 Checking installed version directly...")
169
+ result = subprocess.run([exe_name, "--version"], check=False, capture_output=True, text=True)
170
+ if result.stdout.strip() == "":
171
+ existing_version = None
172
+ print("ℹ️ Could not detect installed version")
173
+ else:
174
+ existing_version = result.stdout.strip()
175
+ print(f"📄 Detected installed version: {existing_version}")
176
+
177
+ if existing_version is not None and version is not None:
178
+ if existing_version == version:
179
+ print(f"✅ {exe_name} is up to date (version {version})")
180
+ print(f"📂 Version information stored at: {INSTALL_VERSION_ROOT}")
181
+ return ("✅ Up to date", version.strip(), version.strip())
182
+ else:
183
+ print(f"🔄 {exe_name} needs update: {existing_version.rstrip()} → {version}")
184
+ tmp_path.write_text(version, encoding="utf-8")
185
+ return ("❌ Outdated", existing_version.strip(), version.strip())
186
+ else:
187
+ print(f"📦 {exe_name} is not installed. Will install version: {version}")
188
+ # tmp_path.write_text(version, encoding="utf-8")
189
+
190
+ print(f"{'=' * 80}")
191
+ return ("⚠️ NotInstalled", "None", version or "unknown")
192
+
193
+
@@ -0,0 +1,191 @@
1
+ """package manager"""
2
+
3
+ from machineconfig.utils.installer_utils.installer_locator_utils import check_if_installed_already
4
+ from machineconfig.utils.installer_utils.installer_class import Installer
5
+ from machineconfig.utils.schemas.installer.installer_types import InstallerData, InstallerDataFiles, get_normalized_arch, get_os_name, OPERATING_SYSTEMS, CPU_ARCHITECTURES
6
+ from machineconfig.jobs.installer.package_groups import PACKAGE_GROUP2NAMES
7
+ from machineconfig.utils.path_extended import PathExtended
8
+ from machineconfig.utils.source_of_truth import INSTALL_VERSION_ROOT, LINUX_INSTALL_PATH
9
+ from machineconfig.utils.io import read_json
10
+
11
+ from rich.console import Console
12
+ from rich.panel import Panel
13
+ from typing import Any, Optional
14
+ import platform
15
+ from joblib import Parallel, delayed
16
+
17
+
18
+ def check_latest():
19
+ console = Console() # Added console initialization
20
+ console.print(Panel("🔍 CHECKING FOR LATEST VERSIONS", title="Status", expand=False)) # Replaced print with Panel
21
+ installers = get_installers(os=get_os_name(), arch=get_normalized_arch(), which_cats=["termabc"])
22
+ installers_github = []
23
+ for inst__ in installers:
24
+ app_name = inst__["appName"]
25
+ repo_url = inst__["repoURL"]
26
+ if "ntop" in app_name:
27
+ print(f"⏭️ Skipping {app_name} (ntop)")
28
+ continue
29
+ if "github" not in repo_url:
30
+ print(f"⏭️ Skipping {app_name} (not a GitHub release)")
31
+ continue
32
+ installers_github.append(inst__)
33
+
34
+ print(f"\n🔍 Checking {len(installers_github)} GitHub-based installers...\n")
35
+
36
+ def func(inst: Installer):
37
+ exe_name = inst.installer_data.get("exeName", "unknown")
38
+ repo_url = inst.installer_data.get("repoURL", "")
39
+ print(f"🔎 Checking {exe_name}...")
40
+ _release_url, version_to_be_installed = inst.get_github_release(repo_url=repo_url, version=None)
41
+ verdict, current_ver, new_ver = check_if_installed_already(exe_name=exe_name, version=version_to_be_installed, use_cache=False)
42
+ return exe_name, verdict, current_ver, new_ver
43
+
44
+ print("\n⏳ Processing installers...\n")
45
+ res = [func(inst) for inst in installers_github]
46
+
47
+ print("\n📊 Generating results table...\n")
48
+
49
+ # Convert to list of dictionaries and group by status
50
+ result_data = []
51
+ for tool, status, current_ver, new_ver in res:
52
+ result_data.append({"Tool": tool, "Status": status, "Current Version": current_ver, "New Version": new_ver})
53
+
54
+ # Group by status
55
+ grouped_data: dict[str, list[dict[str, Any]]] = {}
56
+ for item in result_data:
57
+ status = item["Status"]
58
+ if status not in grouped_data:
59
+ grouped_data[status] = []
60
+ grouped_data[status].append(item)
61
+
62
+ console.print(Panel("📊 INSTALLATION STATUS SUMMARY", title="Status", expand=False))
63
+
64
+ # Print each group
65
+ for status, items in grouped_data.items():
66
+ console.print(f"\n[bold]{status.upper()}:[/bold]")
67
+ console.rule(style="dim")
68
+ for item in items:
69
+ console.print(f" {item['Tool']:<20} | Current: {item['Current Version']:<15} | New: {item['New Version']}")
70
+ console.rule(style="dim")
71
+ console.rule(style="bold blue")
72
+
73
+
74
+ def get_installed_cli_apps():
75
+ print("🔍 LISTING INSTALLED CLI APPS 🔍")
76
+ if platform.system() == "Windows":
77
+ print("🪟 Searching for Windows executables...")
78
+ apps = PathExtended.home().joinpath("AppData/Local/Microsoft/WindowsApps").search("*.exe", not_in=["notepad"])
79
+ elif platform.system() in ["Linux", "Darwin"]:
80
+ print(f"🐧 Searching for {platform.system()} executables...")
81
+ if platform.system() == "Linux":
82
+ apps = PathExtended(LINUX_INSTALL_PATH).search("*") + PathExtended("/usr/local/bin").search("*")
83
+ else: # Darwin/macOS
84
+ apps = PathExtended("/usr/local/bin").search("*") + PathExtended("/opt/homebrew/bin").search("*")
85
+ else:
86
+ error_msg = f"❌ ERROR: System {platform.system()} not supported"
87
+ print(error_msg)
88
+ raise NotImplementedError(error_msg)
89
+ apps = [app for app in apps if app.size("kb") > 0.1 and not app.is_symlink()] # no symlinks like paint and wsl and bash
90
+ print(f"✅ Found {len(apps)} installed applications")
91
+ return apps
92
+
93
+
94
+ def get_installers(os: OPERATING_SYSTEMS, arch: CPU_ARCHITECTURES, which_cats: Optional[list[str]]) -> list[InstallerData]:
95
+ res_all = get_all_installer_data_files()
96
+ acceptable_apps_names: list[str] | None = None
97
+ if which_cats is not None:
98
+ acceptable_apps_names = []
99
+ for cat in which_cats:
100
+ acceptable_apps_names += PACKAGE_GROUP2NAMES[cat]
101
+ else:
102
+ acceptable_apps_names = None
103
+ all_installers: list[InstallerData] = []
104
+ for installer_data in res_all:
105
+ if acceptable_apps_names is not None:
106
+ if installer_data["appName"] not in acceptable_apps_names:
107
+ continue
108
+ try:
109
+ if installer_data["fileNamePattern"][arch][os] is None:
110
+ continue
111
+ except KeyError as ke:
112
+ print(f"❌ ERROR: Missing key in installer data: {ke}")
113
+ print(f"Installer data: {installer_data}")
114
+ raise KeyError(f"Missing key in installer data: {ke}")
115
+ all_installers.append(installer_data)
116
+ return all_installers
117
+
118
+
119
+ def get_all_installer_data_files() -> list[InstallerData]:
120
+ import machineconfig.jobs.installer as module
121
+ from pathlib import Path
122
+ res_raw: InstallerDataFiles = read_json(Path(module.__file__).parent.joinpath("installer_data.json"))
123
+ res_final: list[InstallerData] = res_raw["installers"]
124
+ return res_final
125
+
126
+
127
+ def install_bulk(installers_data: list[InstallerData], safe: bool = False, jobs: int = 10, fresh: bool = False):
128
+ print("🚀 BULK INSTALLATION PROCESS 🚀")
129
+ if fresh:
130
+ print("🧹 Fresh install requested - clearing version cache...")
131
+ PathExtended(INSTALL_VERSION_ROOT).delete(sure=True)
132
+ print("✅ Version cache cleared")
133
+ if safe:
134
+ pass
135
+ print(f"🚀 Starting installation of {len(installers_data)} packages...")
136
+ print("📦 INSTALLING FIRST PACKAGE 📦")
137
+ Installer(installers_data[0]).install(version=None)
138
+ installers_remaining = installers_data[1:]
139
+ print("📦 INSTALLING REMAINING PACKAGES 📦")
140
+
141
+ # Use joblib for parallel processing of remaining installers
142
+ res = Parallel(n_jobs=jobs)(delayed(lambda x: Installer(x).install_robust(version=None))(installer) for installer in installers_remaining)
143
+
144
+ console = Console()
145
+
146
+ print("\n")
147
+ console.rule("📊 INSTALLATION RESULTS SUMMARY 📊")
148
+
149
+ print("\n")
150
+ console.rule("✓ Same Version Apps")
151
+ same_version_results = [r for r in res if r and "same version" in str(r)]
152
+ for result in same_version_results:
153
+ print(f" {result}")
154
+
155
+ print("\n")
156
+ console.rule("⬆️ Updated Apps")
157
+ updated_results = [r for r in res if r and "updated from" in str(r)]
158
+ for result in updated_results:
159
+ print(f" {result}")
160
+
161
+ print("\n")
162
+ console.rule("❌ Failed Apps")
163
+ failed_results = [r for r in res if r and "Failed at" in str(r)]
164
+ for result in failed_results:
165
+ print(f" {result}")
166
+
167
+ print("\n")
168
+ print("✨ INSTALLATION COMPLETE ✨".center(100, "="))
169
+ print("\n" * 2)
170
+
171
+
172
+ def get_machineconfig_version() -> str:
173
+ from importlib.metadata import PackageNotFoundError, version as _pkg_version
174
+ from pathlib import Path
175
+ import tomllib
176
+ name: str = "machineconfig"
177
+ try:
178
+ return _pkg_version(name)
179
+ except PackageNotFoundError:
180
+ pass
181
+ root: Path = Path(__file__).resolve().parents[2]
182
+ pyproject: Path = root / "pyproject.toml"
183
+ if pyproject.is_file():
184
+ with pyproject.open("rb") as f:
185
+ data: dict[str, object] = tomllib.load(f)
186
+ project = data.get("project")
187
+ if isinstance(project, dict):
188
+ version = project.get("version")
189
+ if isinstance(version, str) and version:
190
+ return version
191
+ return "0.0.0"
machineconfig/utils/io.py CHANGED
@@ -1,4 +1,3 @@
1
- from __future__ import annotations
2
1
 
3
2
  from typing import Any, Union, Optional, Mapping
4
3
  from pathlib import Path
@@ -35,24 +34,6 @@ def save_json(obj: Any, path: PathLike, indent: Optional[int] = None, verbose: b
35
34
  return Path(path_obj)
36
35
 
37
36
 
38
- # def save_toml(obj: Mapping[str, Any], path: PathLike, verbose: bool = False) -> Path:
39
- # path_obj = _ensure_parent(path)
40
- # with open(path_obj, "w", encoding="utf-8") as fh:
41
- # toml.dump(obj, fh)
42
- # if verbose:
43
- # print(f"Saved toml -> {path_obj}")
44
- # return Path(path_obj)
45
-
46
-
47
- # def save_yaml(obj: Any, path: PathLike, verbose: bool = False) -> Path:
48
- # path_obj = _ensure_parent(path)
49
- # with open(path_obj, "w", encoding="utf-8") as fh:
50
- # yaml.safe_dump(obj, fh, sort_keys=False)
51
- # if verbose:
52
- # print(f"Saved yaml -> {path_obj}")
53
- # return Path(path_obj)
54
-
55
-
56
37
  def save_ini(path: PathLike, obj: Mapping[str, Mapping[str, Any]], verbose: bool = False) -> Path:
57
38
  cp = configparser.ConfigParser()
58
39
  for section, values in obj.items():
@@ -69,7 +50,6 @@ def read_ini(path: "Path", encoding: Optional[str] = None):
69
50
  if not Path(path).exists() or Path(path).is_dir():
70
51
  raise FileNotFoundError(f"File not found or is a directory: {path}")
71
52
  import configparser
72
-
73
53
  res = configparser.ConfigParser()
74
54
  res.read(filenames=[str(path)], encoding=encoding)
75
55
  return res
@@ -77,13 +57,17 @@ def read_ini(path: "Path", encoding: Optional[str] = None):
77
57
 
78
58
  def read_json(path: "Path", r: bool = False, **kwargs: Any) -> Any: # return could be list or dict etc
79
59
  import json
80
-
81
60
  try:
82
61
  mydict = json.loads(Path(path).read_text(encoding="utf-8"), **kwargs)
83
62
  except Exception:
84
- import pyjson5
85
-
86
- mydict = pyjson5.loads(Path(path).read_text(encoding="utf-8"), **kwargs) # file has C-style comments.
63
+ import re
64
+ def remove_comments(text: str) -> str:
65
+ # remove all // single-line comments
66
+ text = re.sub(r'//.*', '', text)
67
+ # remove all /* … */ block comments (non-greedy)
68
+ text = re.sub(r'/\*.*?\*/', '', text, flags=re.DOTALL)
69
+ return text
70
+ mydict = json.loads(remove_comments(Path(path).read_text(encoding="utf-8")), **kwargs)
87
71
  _ = r
88
72
  return mydict
89
73
 
@@ -92,3 +76,72 @@ def from_pickle(path: Path) -> Any:
92
76
  import pickle
93
77
 
94
78
  return pickle.loads(path.read_bytes())
79
+
80
+
81
+ def pwd2key(password: str, salt: Optional[bytes] = None, iterations: int = 10) -> bytes: # Derive a secret key from a given password and salt"""
82
+ import base64
83
+ if salt is None:
84
+ import hashlib
85
+ m = hashlib.sha256()
86
+ m.update(password.encode(encoding="utf-8"))
87
+ return base64.urlsafe_b64encode(s=m.digest()) # make url-safe bytes required by Ferent.
88
+ from cryptography.hazmat.primitives import hashes
89
+ from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
90
+ return base64.urlsafe_b64encode(PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=salt, iterations=iterations, backend=None).derive(password.encode()))
91
+
92
+
93
+ def encrypt(msg: bytes, key: Optional[bytes] = None, pwd: Optional[str] = None, salted: bool = True, iteration: Optional[int] = None, gen_key: bool = False) -> bytes:
94
+ import base64
95
+ from cryptography.fernet import Fernet
96
+
97
+ salt, iteration = None, None
98
+ if pwd is not None: # generate it from password
99
+ assert (key is None) and (type(pwd) is str), "❌ You can either pass key or pwd, or none of them, but not both."
100
+ import secrets
101
+ iteration = iteration or secrets.randbelow(exclusive_upper_bound=1_000_000)
102
+ salt = secrets.token_bytes(nbytes=16) if salted else None
103
+ key_resolved = pwd2key(password=pwd, salt=salt, iterations=iteration)
104
+ elif key is None:
105
+ if gen_key:
106
+ key_resolved = Fernet.generate_key()
107
+ Path.home().joinpath("dotfiles/creds/data/encrypted_files_key.bytes").write_bytes(key_resolved)
108
+ else:
109
+ try:
110
+ key_resolved = Path.home().joinpath("dotfiles/creds/data/encrypted_files_key.bytes").read_bytes()
111
+ print(f"⚠️ Using key from: {Path.home().joinpath('dotfiles/creds/data/encrypted_files_key.bytes')}")
112
+ except FileNotFoundError as err:
113
+ print("\n" * 3, "~" * 50, """Consider Loading up your dotfiles or pass `gen_key=True` to make and save one.""", "~" * 50, "\n" * 3)
114
+ raise FileNotFoundError(err) from err
115
+ elif isinstance(key, (str, Path)):
116
+ key_resolved = Path(key).read_bytes() # a path to a key file was passed, read it:
117
+ elif type(key) is bytes:
118
+ key_resolved = key # key passed explicitly
119
+ else:
120
+ raise TypeError("❌ Key must be either a path, bytes object or None.")
121
+ code = Fernet(key=key_resolved).encrypt(msg)
122
+ if pwd is not None and salt is not None and iteration is not None:
123
+ return base64.urlsafe_b64encode(b"%b%b%b" % (salt, iteration.to_bytes(4, "big"), base64.urlsafe_b64decode(code)))
124
+ return code
125
+
126
+
127
+ def decrypt(token: bytes, key: Optional[bytes] = None, pwd: Optional[str] = None, salted: bool = True) -> bytes:
128
+ import base64
129
+ if pwd is not None:
130
+ assert key is None, "❌ You can either pass key or pwd, or none of them, but not both."
131
+ if salted:
132
+ decoded = base64.urlsafe_b64decode(token)
133
+ salt, iterations, token = decoded[:16], decoded[16:20], base64.urlsafe_b64encode(decoded[20:])
134
+ key_resolved = pwd2key(password=pwd, salt=salt, iterations=int.from_bytes(bytes=iterations, byteorder="big"))
135
+ else:
136
+ key_resolved = pwd2key(password=pwd) # trailing `;` prevents IPython from caching the result.
137
+ elif type(key) is bytes:
138
+ assert pwd is None, "❌ You can either pass key or pwd, or none of them, but not both."
139
+ key_resolved = key # passsed explicitly
140
+ elif key is None:
141
+ key_resolved = Path.home().joinpath("dotfiles/creds/data/encrypted_files_key.bytes").read_bytes() # read from file
142
+ elif isinstance(key, (str, Path)):
143
+ key_resolved = Path(key).read_bytes() # passed a path to a file containing kwy
144
+ else:
145
+ raise TypeError(f"❌ Key must be either str, P, Path, bytes or None. Recieved: {type(key)}")
146
+ from cryptography.fernet import Fernet
147
+ return Fernet(key=key_resolved).decrypt(token)