machineconfig 7.50__py3-none-any.whl → 8.14__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 (298) hide show
  1. machineconfig/cluster/remote/cloud_manager.py +1 -1
  2. machineconfig/cluster/sessions_managers/utils/maker.py +23 -11
  3. machineconfig/cluster/sessions_managers/wt_local_manager.py +22 -19
  4. machineconfig/cluster/sessions_managers/wt_remote_manager.py +3 -1
  5. machineconfig/cluster/sessions_managers/zellij_local_manager.py +3 -1
  6. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +3 -2
  7. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +2 -2
  8. machineconfig/jobs/installer/installer_data.json +1185 -165
  9. machineconfig/jobs/installer/linux_scripts/q.sh +10 -7
  10. machineconfig/jobs/installer/linux_scripts/redis.sh +1 -0
  11. machineconfig/jobs/installer/package_groups.py +52 -84
  12. machineconfig/jobs/installer/powershell_scripts/install_fonts.ps1 +129 -34
  13. machineconfig/jobs/installer/{custom → python_scripts}/boxes.py +2 -2
  14. machineconfig/jobs/installer/{custom_dev → python_scripts}/brave.py +5 -3
  15. machineconfig/jobs/installer/python_scripts/cloudflare_warp_cli.py +23 -0
  16. machineconfig/jobs/installer/{custom_dev → python_scripts}/code.py +4 -1
  17. machineconfig/jobs/installer/{custom_dev → python_scripts}/dubdb_adbc.py +1 -1
  18. machineconfig/jobs/installer/{custom → python_scripts}/hx.py +16 -12
  19. machineconfig/jobs/installer/{custom_dev → python_scripts}/nerdfont.py +2 -2
  20. machineconfig/jobs/installer/{custom_dev → python_scripts}/nerfont_windows_helper.py +27 -22
  21. machineconfig/jobs/installer/python_scripts/sysabc.py +139 -0
  22. machineconfig/jobs/installer/{custom_dev → python_scripts}/wezterm.py +2 -19
  23. machineconfig/jobs/installer/{custom_dev → python_scripts}/winget.py +10 -14
  24. machineconfig/jobs/installer/python_scripts/yazi.py +121 -0
  25. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_nfs +0 -1
  26. machineconfig/jobs/scripts/powershell_scripts/mount_ssh.ps1 +13 -0
  27. machineconfig/jobs/scripts/powershell_scripts/obs.ps1 +4 -0
  28. machineconfig/jobs/scripts_dynamic/a.py +25 -0
  29. machineconfig/logger.py +0 -1
  30. machineconfig/profile/create_helper.py +21 -22
  31. machineconfig/profile/create_links_export.py +25 -11
  32. machineconfig/profile/create_shell_profile.py +14 -3
  33. machineconfig/profile/mapper.toml +8 -6
  34. machineconfig/scripts/__init__.py +0 -4
  35. machineconfig/scripts/linux/wrap_mcfg +20 -21
  36. machineconfig/scripts/python/agents.py +74 -50
  37. machineconfig/scripts/python/ai/initai.py +1 -1
  38. machineconfig/scripts/python/ai/scripts/command_runner.ps1 +33 -0
  39. machineconfig/scripts/python/ai/{command_runner → scripts}/command_runner.sh +1 -1
  40. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +1 -1
  41. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Thinking-Beast-Mode.chatmode.md → agents/Thinking-Beast-Mode.agent.md} +0 -1
  42. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md → agents/Ultimate-Transparent-Thinking-Beast-Mode.agent.md} +0 -1
  43. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/deepResearch.chatmode.md → agents/deepResearch.agent.md} +2 -2
  44. machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +5 -5
  45. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +4 -0
  46. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/watch_exec.prompt.md +20 -0
  47. machineconfig/scripts/python/ai/solutions/generic.py +1 -1
  48. machineconfig/scripts/python/ai/{generate_files.py → utils/generate_files.py} +2 -2
  49. machineconfig/scripts/python/cloud.py +6 -6
  50. machineconfig/scripts/python/croshell.py +67 -60
  51. machineconfig/scripts/python/devops.py +41 -21
  52. machineconfig/scripts/python/devops_navigator.py +0 -4
  53. machineconfig/scripts/python/env_manager/env_manager_tui.py +204 -0
  54. machineconfig/scripts/python/env_manager/path_manager_tui.py +1 -1
  55. machineconfig/scripts/python/fire_jobs.py +95 -67
  56. machineconfig/scripts/python/ftpx.py +44 -17
  57. machineconfig/scripts/python/helpers/ast_search.py +74 -0
  58. machineconfig/scripts/python/helpers/qr_code.py +166 -0
  59. machineconfig/scripts/python/helpers/repo_rag.py +325 -0
  60. machineconfig/scripts/python/helpers/symantic_search.py +25 -0
  61. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.json +1 -1
  62. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.py +9 -7
  63. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_gemini.py +21 -8
  64. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_qwen.py +0 -12
  65. machineconfig/scripts/python/helpers_agents/fire_agents_help_launch.py +30 -11
  66. machineconfig/scripts/python/helpers_agents/fire_agents_helper_types.py +9 -2
  67. machineconfig/scripts/python/helpers_agents/privacy/configs/aichat/config.yaml +5 -0
  68. machineconfig/scripts/python/helpers_agents/privacy/configs/aider/.aider.conf.yml +2 -0
  69. machineconfig/scripts/python/helpers_agents/privacy/configs/copilot/config.yml +1 -0
  70. machineconfig/scripts/python/helpers_agents/privacy/configs/crush/crush.json +10 -0
  71. machineconfig/scripts/python/helpers_agents/privacy/configs/gemini/settings.json +12 -0
  72. machineconfig/scripts/python/helpers_agents/privacy/privacy.py +109 -0
  73. machineconfig/scripts/python/helpers_agents/templates/prompt.txt +8 -4
  74. machineconfig/scripts/python/helpers_agents/templates/template.sh +18 -8
  75. machineconfig/scripts/python/helpers_cloud/cloud_copy.py +28 -21
  76. machineconfig/scripts/python/helpers_cloud/cloud_helpers.py +1 -1
  77. machineconfig/scripts/python/helpers_cloud/cloud_mount.py +19 -17
  78. machineconfig/scripts/python/helpers_cloud/cloud_sync.py +8 -7
  79. machineconfig/scripts/python/helpers_croshell/crosh.py +3 -3
  80. machineconfig/scripts/python/helpers_croshell/start_slidev.py +6 -7
  81. machineconfig/scripts/python/helpers_devops/cli_config.py +19 -25
  82. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +22 -13
  83. machineconfig/scripts/python/helpers_devops/cli_nw.py +113 -26
  84. machineconfig/scripts/python/helpers_devops/cli_repos.py +37 -11
  85. machineconfig/scripts/python/helpers_devops/cli_self.py +95 -42
  86. machineconfig/scripts/python/helpers_devops/cli_share_file.py +9 -9
  87. machineconfig/scripts/python/helpers_devops/cli_share_server.py +13 -12
  88. machineconfig/scripts/python/helpers_devops/{cli_terminal.py → cli_share_terminal.py} +15 -17
  89. machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py +4 -4
  90. machineconfig/scripts/python/helpers_devops/devops_status.py +7 -19
  91. machineconfig/scripts/python/helpers_devops/run_script.py +180 -0
  92. machineconfig/scripts/python/helpers_devops/themes/choose_wezterm_theme.py +1 -1
  93. machineconfig/scripts/python/helpers_fire_command/file_wrangler.py +2 -19
  94. machineconfig/scripts/python/helpers_fire_command/fire_jobs_args_helper.py +1 -0
  95. machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +25 -15
  96. machineconfig/scripts/python/helpers_msearch/scripts_linux/fzfg +3 -3
  97. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfg.ps1 +58 -1
  98. machineconfig/scripts/python/helpers_navigator/command_tree.py +50 -18
  99. machineconfig/scripts/python/helpers_network/address.py +176 -0
  100. machineconfig/scripts/python/helpers_network/address_switch.py +78 -0
  101. machineconfig/scripts/python/{nw → helpers_network}/mount_nfs.py +2 -2
  102. machineconfig/scripts/python/{nw → helpers_network}/mount_ssh.py +1 -1
  103. machineconfig/scripts/python/{nw/devops_add_identity.py → helpers_network/ssh_add_identity.py} +35 -1
  104. machineconfig/scripts/python/{nw/devops_add_ssh_key.py → helpers_network/ssh_add_ssh_key.py} +26 -7
  105. machineconfig/scripts/python/{nw → helpers_network}/ssh_debug_linux.py +7 -7
  106. machineconfig/scripts/python/{nw → helpers_network}/ssh_debug_windows.py +4 -4
  107. machineconfig/scripts/python/helpers_repos/clone.py +0 -1
  108. machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +13 -5
  109. machineconfig/scripts/python/helpers_repos/entrypoint.py +2 -1
  110. machineconfig/scripts/python/helpers_repos/record.py +2 -1
  111. machineconfig/scripts/python/helpers_repos/repo_analyzer_1.py +160 -0
  112. machineconfig/scripts/python/helpers_repos/{count_lines.py → repo_analyzer_2.py} +113 -192
  113. machineconfig/scripts/python/helpers_sessions/sessions_multiprocess.py +19 -13
  114. machineconfig/scripts/python/helpers_utils/download.py +150 -0
  115. machineconfig/scripts/python/helpers_utils/pdf.py +96 -0
  116. machineconfig/scripts/python/helpers_utils/python.py +187 -0
  117. machineconfig/scripts/python/interactive.py +30 -31
  118. machineconfig/scripts/python/{machineconfig.py → mcfg_entry.py} +4 -5
  119. machineconfig/scripts/python/msearch.py +57 -6
  120. machineconfig/scripts/python/sessions.py +100 -31
  121. machineconfig/scripts/python/terminal.py +26 -17
  122. machineconfig/scripts/python/utils.py +17 -15
  123. machineconfig/scripts/windows/wrap_mcfg.ps1 +6 -3
  124. machineconfig/settings/lf/windows/lfcd.ps1 +1 -1
  125. machineconfig/settings/linters/.ruff.toml +1 -1
  126. machineconfig/settings/shells/bash/init.sh +29 -2
  127. machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +1 -1
  128. machineconfig/settings/shells/nushell/config.nu +2 -2
  129. machineconfig/settings/shells/nushell/env.nu +45 -6
  130. machineconfig/settings/shells/nushell/init.nu +282 -95
  131. machineconfig/settings/shells/pwsh/init.ps1 +1 -0
  132. machineconfig/settings/shells/wezterm/wezterm.lua +2 -0
  133. machineconfig/settings/shells/zsh/init.sh +1 -8
  134. machineconfig/settings/television/cable_unix/alias.toml +8 -0
  135. machineconfig/settings/television/cable_unix/aws-buckets.toml +14 -0
  136. machineconfig/settings/television/cable_unix/aws-instances.toml +13 -0
  137. machineconfig/settings/television/cable_unix/bash-history.toml +8 -0
  138. machineconfig/settings/television/cable_unix/channels.toml +19 -0
  139. machineconfig/settings/television/cable_unix/dirs.toml +13 -0
  140. machineconfig/settings/television/cable_unix/distrobox-list.toml +42 -0
  141. machineconfig/settings/television/cable_unix/docker-images.toml +13 -0
  142. machineconfig/settings/television/cable_unix/dotfiles.toml +11 -0
  143. machineconfig/settings/television/cable_unix/env.toml +17 -0
  144. machineconfig/settings/television/cable_unix/files.toml +11 -0
  145. machineconfig/settings/television/cable_unix/fish-history.toml +8 -0
  146. machineconfig/settings/television/cable_unix/git-branch.toml +11 -0
  147. machineconfig/settings/television/cable_unix/git-diff.toml +10 -0
  148. machineconfig/settings/television/cable_unix/git-log.toml +12 -0
  149. machineconfig/settings/television/cable_unix/git-reflog.toml +12 -0
  150. machineconfig/settings/television/cable_unix/git-repos.toml +16 -0
  151. machineconfig/settings/television/cable_unix/guix.toml +20 -0
  152. machineconfig/settings/television/cable_unix/just-recipes.toml +18 -0
  153. machineconfig/settings/television/cable_unix/k8s-deployments.toml +36 -0
  154. machineconfig/settings/television/cable_unix/k8s-pods.toml +50 -0
  155. machineconfig/settings/television/cable_unix/k8s-services.toml +36 -0
  156. machineconfig/settings/television/cable_unix/man-pages.toml +24 -0
  157. machineconfig/settings/television/cable_unix/nu-history.toml +7 -0
  158. machineconfig/settings/television/cable_unix/procs.toml +20 -0
  159. machineconfig/settings/television/cable_unix/text.toml +17 -0
  160. machineconfig/settings/television/cable_unix/tldr.toml +18 -0
  161. machineconfig/settings/television/cable_unix/zsh-history.toml +9 -0
  162. machineconfig/settings/television/cable_windows/alias.toml +7 -0
  163. machineconfig/settings/television/cable_windows/dirs.toml +13 -0
  164. machineconfig/settings/television/cable_windows/docker-images.toml +13 -0
  165. machineconfig/settings/television/cable_windows/dotfiles.toml +11 -0
  166. machineconfig/settings/television/cable_windows/env.toml +17 -0
  167. machineconfig/settings/television/cable_windows/files.toml +14 -0
  168. machineconfig/settings/television/cable_windows/git-branch.toml +11 -0
  169. machineconfig/settings/television/cable_windows/git-diff.toml +10 -0
  170. machineconfig/settings/television/cable_windows/git-log.toml +11 -0
  171. machineconfig/settings/television/cable_windows/git-reflog.toml +11 -0
  172. machineconfig/settings/television/cable_windows/git-repos.toml +15 -0
  173. machineconfig/settings/television/cable_windows/nu-history.toml +7 -0
  174. machineconfig/settings/television/cable_windows/pwsh-history.toml +6 -0
  175. machineconfig/settings/television/cable_windows/text.toml +17 -0
  176. machineconfig/settings/wt/__init__.py +0 -0
  177. machineconfig/settings/yazi/init.lua +49 -24
  178. machineconfig/settings/yazi/keymap_linux.toml +19 -4
  179. machineconfig/settings/yazi/keymap_windows.toml +0 -1
  180. machineconfig/settings/yazi/shell/yazi_cd.ps1 +29 -5
  181. machineconfig/settings/yazi/theme.toml +4 -0
  182. machineconfig/settings/yazi/yazi_linux.toml +84 -0
  183. machineconfig/settings/yazi/yazi_windows.toml +58 -0
  184. machineconfig/settings/zellij/layouts/st.kdl +39 -8
  185. machineconfig/setup_linux/__init__.py +1 -2
  186. machineconfig/setup_linux/apps_desktop.sh +8 -27
  187. machineconfig/setup_linux/web_shortcuts/interactive.sh +12 -10
  188. machineconfig/setup_linux/web_shortcuts/live_from_github.sh +31 -0
  189. machineconfig/setup_mac/__init__.py +2 -3
  190. machineconfig/setup_windows/__init__.py +3 -5
  191. machineconfig/setup_windows/ssh/openssh-server.ps1 +1 -1
  192. machineconfig/setup_windows/uv.ps1 +8 -1
  193. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +12 -10
  194. machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +30 -0
  195. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +17 -0
  196. machineconfig/utils/accessories.py +7 -4
  197. machineconfig/utils/code.py +69 -27
  198. machineconfig/utils/files/headers.py +2 -2
  199. machineconfig/utils/installer_utils/github_release_bulk.py +156 -119
  200. machineconfig/utils/installer_utils/install_from_url.py +183 -0
  201. machineconfig/utils/installer_utils/installer_class.py +43 -100
  202. machineconfig/utils/installer_utils/installer_cli.py +175 -0
  203. machineconfig/utils/installer_utils/installer_helper.py +129 -0
  204. machineconfig/utils/installer_utils/{installer_abc.py → installer_locator_utils.py} +36 -85
  205. machineconfig/utils/{installer.py → installer_utils/installer_runner.py} +16 -59
  206. machineconfig/utils/io.py +0 -1
  207. machineconfig/utils/links.py +2 -2
  208. machineconfig/utils/meta.py +30 -16
  209. machineconfig/utils/options.py +42 -24
  210. machineconfig/utils/options_tv.py +119 -0
  211. machineconfig/utils/path_extended.py +42 -20
  212. machineconfig/utils/path_helper.py +75 -22
  213. machineconfig/utils/procs.py +1 -1
  214. machineconfig/utils/scheduler.py +20 -53
  215. machineconfig/utils/schemas/layouts/layout_types.py +1 -1
  216. machineconfig/utils/ssh.py +159 -418
  217. machineconfig/utils/ssh_utils/abc.py +5 -0
  218. machineconfig/utils/ssh_utils/copy_from_here.py +111 -0
  219. machineconfig/utils/ssh_utils/copy_to_here.py +303 -0
  220. machineconfig/utils/ssh_utils/utils.py +142 -0
  221. machineconfig/utils/ssh_utils/wsl.py +210 -0
  222. machineconfig/utils/terminal.py +1 -0
  223. machineconfig/utils/upgrade_packages.py +6 -1
  224. machineconfig/utils/ve.py +12 -4
  225. machineconfig-8.14.dist-info/METADATA +132 -0
  226. {machineconfig-7.50.dist-info → machineconfig-8.14.dist-info}/RECORD +264 -215
  227. {machineconfig-7.50.dist-info → machineconfig-8.14.dist-info}/entry_points.txt +2 -4
  228. machineconfig/jobs/installer/linux_scripts/pgsql.sh +0 -41
  229. machineconfig/jobs/installer/linux_scripts/timescaledb.sh +0 -71
  230. machineconfig/jobs/installer/powershell_scripts/archive_pygraphviz.ps1 +0 -12
  231. machineconfig/jobs/installer/powershell_scripts/openssh-server_add_key.ps1 +0 -7
  232. machineconfig/jobs/installer/powershell_scripts/openssh-server_copy-ssh-id.ps1 +0 -14
  233. machineconfig/scripts/linux/other/switch_ip +0 -20
  234. machineconfig/scripts/python/ai/command_runner/prompt.txt +0 -9
  235. machineconfig/scripts/python/define.py +0 -31
  236. machineconfig/scripts/python/explore.py +0 -49
  237. machineconfig/scripts/python/helpers_devops/cli_utils.py +0 -246
  238. machineconfig/scripts/python/helpers_msearch/scripts_linux/fzfag +0 -17
  239. machineconfig/scripts/python/helpers_msearch/scripts_linux/fzfrga +0 -21
  240. machineconfig/scripts/python/helpers_msearch/scripts_linux/skrg +0 -4
  241. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfb.ps1 +0 -3
  242. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfrga.bat +0 -20
  243. machineconfig/scripts/python/helpers_repos/count_lines_frontend.py +0 -17
  244. machineconfig/scripts/python/nw/add_ssh_key.py +0 -148
  245. machineconfig/scripts/python/nw/wsl_windows_transfer.py +0 -66
  246. machineconfig/scripts/windows/mounts/mount_ssh.ps1 +0 -13
  247. machineconfig/settings/lf/linux/exe/fzf_nano.sh +0 -16
  248. machineconfig/settings/lf/windows/fzf_edit.ps1 +0 -6
  249. machineconfig/settings/lf/windows/tst.ps1 +0 -1
  250. machineconfig/settings/yazi/yazi.toml +0 -17
  251. machineconfig/setup_linux/apps.sh +0 -66
  252. machineconfig/setup_linux/others/cli_installation.sh +0 -137
  253. machineconfig/setup_linux/others/mint_keyboard_shortcuts.sh +0 -30
  254. machineconfig/setup_linux/ssh/openssh_all.sh +0 -25
  255. machineconfig/setup_linux/ssh/openssh_wsl.sh +0 -38
  256. machineconfig/setup_mac/apps.sh +0 -73
  257. machineconfig/setup_windows/apps.ps1 +0 -62
  258. machineconfig/setup_windows/others/obs.ps1 +0 -4
  259. machineconfig/setup_windows/ssh/add_identity.ps1 +0 -11
  260. machineconfig/utils/installer_utils/installer.py +0 -221
  261. machineconfig-7.50.dist-info/METADATA +0 -92
  262. /machineconfig/jobs/installer/linux_scripts/{warp-cli.sh → cloudflare_warp_cli.sh} +0 -0
  263. /machineconfig/jobs/installer/{custom_dev → python_scripts}/__init__.py +0 -0
  264. /machineconfig/jobs/installer/{custom_dev → python_scripts}/alacritty.py +0 -0
  265. /machineconfig/jobs/installer/{custom_dev → python_scripts}/bypass_paywall.py +0 -0
  266. /machineconfig/jobs/installer/{custom_dev → python_scripts}/cursor.py +0 -0
  267. /machineconfig/jobs/installer/{custom_dev → python_scripts}/espanso.py +0 -0
  268. /machineconfig/jobs/installer/{custom → python_scripts}/gh.py +0 -0
  269. /machineconfig/jobs/installer/{custom_dev → python_scripts}/goes.py +0 -0
  270. /machineconfig/jobs/installer/{custom_dev → python_scripts}/lvim.py +0 -0
  271. /machineconfig/jobs/installer/{custom_dev → python_scripts}/redis.py +0 -0
  272. /machineconfig/{setup_linux/others → jobs/scripts/bash_scripts}/android.sh +0 -0
  273. /machineconfig/jobs/{installer/linux_scripts → scripts/bash_scripts}/lid.sh +0 -0
  274. /machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_drive +0 -0
  275. /machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_nw_drive +0 -0
  276. /machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_smb +0 -0
  277. /machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_cloud.sh +0 -0
  278. /machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_nfs +0 -0
  279. /machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/start_docker +0 -0
  280. /machineconfig/{scripts → jobs/scripts/powershell_scripts}/Restore-ThunderbirdProfile.ps1 +0 -0
  281. /machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/docker.ps1 +0 -0
  282. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nfs.ps1 +0 -0
  283. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nw.ps1 +0 -0
  284. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_smb.ps1 +0 -0
  285. /machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/power_options.ps1 +0 -0
  286. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_cloud.cmd +0 -0
  287. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_smb.ps1 +0 -0
  288. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/unlock_bitlocker.ps1 +0 -0
  289. /machineconfig/scripts/python/{nw → ai/utils}/__init__.py +0 -0
  290. /machineconfig/scripts/python/ai/{vscode_tasks.py → utils/vscode_tasks.py} +0 -0
  291. /machineconfig/{settings/shells/pwsh/profile.ps1 → scripts/python/helpers_fire_command/f.py} +0 -0
  292. /machineconfig/{setup_windows/wt_and_pwsh → scripts/python/helpers_network}/__init__.py +0 -0
  293. /machineconfig/scripts/python/{nw → helpers_network}/mount_nw_drive.py +0 -0
  294. /machineconfig/scripts/python/{nw → helpers_network}/onetimeshare.py +0 -0
  295. /machineconfig/scripts/python/{nw → helpers_network}/wifi_conn.py +0 -0
  296. /machineconfig/{setup_windows/wt_and_pwsh → settings/wt}/set_wt_settings.py +0 -0
  297. {machineconfig-7.50.dist-info → machineconfig-8.14.dist-info}/WHEEL +0 -0
  298. {machineconfig-7.50.dist-info → machineconfig-8.14.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,14 +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
4
- from machineconfig.utils.installer_utils.installer_abc import check_tool_exists
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
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
+ )
6
10
 
7
11
  import platform
8
12
  import subprocess
9
- import json
10
- from typing import Optional, Any
11
- from urllib.parse import urlparse
13
+ from typing import Optional
12
14
 
13
15
 
14
16
  class Installer:
@@ -42,10 +44,8 @@ class Installer:
42
44
  result_new = subprocess.run(f"{exe_name} --version", shell=True, capture_output=True, text=True)
43
45
  new_version_cli = result_new.stdout.strip()
44
46
  if old_version_cli == new_version_cli:
45
- # print(f"ℹ️ Same version detected: {old_version_cli}")
46
47
  return f"""📦️ 😑 {exe_name}, same version: {old_version_cli}"""
47
48
  else:
48
- # print(f"🚀 Update successful: {old_version_cli} ➡️ {new_version_cli}")
49
49
  return f"""📦️ 🤩 {exe_name} updated from {old_version_cli} ➡️ TO ➡️ {new_version_cli}"""
50
50
  except Exception as ex:
51
51
  exe_name = self._get_exe_name()
@@ -63,24 +63,25 @@ class Installer:
63
63
  raise ValueError(f"No installation pattern for {exe_name} on {os_name} {arch}")
64
64
  version_to_be_installed: str = "unknown" # Initialize to ensure it's always bound
65
65
  if repo_url == "CMD":
66
- if any(pm in installer_arch_os for pm in ["npm ", "pip ", "winget ", "brew ", "curl "]):
66
+ if any(pm in installer_arch_os for pm in ["npm ", "pip ", "winget ", "brew ", "curl ", "sudo"]):
67
+ from rich import print as rprint
68
+ from rich.panel import Panel
69
+ from rich.console import Group
67
70
  package_manager = installer_arch_os.split(" ", maxsplit=1)[0]
68
71
  print(f"📦 Using package manager: {installer_arch_os}")
69
72
  desc = package_manager + " installation"
70
73
  version_to_be_installed = package_manager + "Latest"
71
- result = subprocess.run(installer_arch_os, shell=True, capture_output=True, text=False)
72
- # from machineconfig.utils.code import run_shell_script
73
- # result = run_shell_script(installer_arch_os)
74
- success = result.returncode == 0 and result.stderr == "".encode()
74
+ result = subprocess.run(installer_arch_os, shell=True, capture_output=False, text=True)
75
+ success = result.returncode == 0 and result.stderr == ""
75
76
  if not success:
76
- print(f"❌ {desc} failed")
77
+ sub_panels = []
77
78
  if result.stdout:
78
- print(f"STDOUT: {result.stdout}")
79
+ sub_panels.append(Panel(result.stdout, title="STDOUT", style="blue"))
79
80
  if result.stderr:
80
- print(f"STDERR: {result.stderr}")
81
- print(f"Return code: {result.returncode}")
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"))
82
84
  elif installer_arch_os.endswith((".sh", ".py", ".ps1")):
83
- # search for the script, see which path ends with the script name
84
85
  import machineconfig.jobs.installer as module
85
86
  from pathlib import Path
86
87
  search_root = Path(module.__file__).parent
@@ -105,14 +106,11 @@ class Installer:
105
106
  import runpy
106
107
  runpy.run_path(str(installer_path), run_name=None)["main"](self.installer_data, version=version)
107
108
  version_to_be_installed = str(version)
108
- elif installer_arch_os.startswith("https://"): # its a url to be downloaded
109
- downloaded_object = PathExtended(installer_arch_os).download(folder=INSTALL_TMP_DIR)
110
- # object is either a zip containing a binary or a straight out binary.
111
- if downloaded_object.suffix in [".zip", ".tar.gz"]:
112
- downloaded_object = downloaded_object.decompress()
109
+ elif installer_arch_os.startswith("https://") or installer_arch_os.startswith("http://"):
110
+ downloaded_object = download_and_prepare(installer_arch_os)
113
111
  if downloaded_object.suffix in [".exe", ""]: # likely an executable
114
112
  if platform.system() == "Windows":
115
- 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")
116
114
  elif platform.system() in ["Linux", "Darwin"]:
117
115
  system_name = "Linux" if platform.system() == "Linux" else "macOS"
118
116
  print(f"🐧 Installing on {system_name}...")
@@ -131,29 +129,20 @@ class Installer:
131
129
  print(f"🔄 Renaming to correct name: {new_exe_name}")
132
130
  exe.with_name(name=new_exe_name, inplace=True, overwrite=True)
133
131
  version_to_be_installed = "downloaded_binary"
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}")
134
137
  else:
135
138
  raise NotImplementedError(f"CMD installation method not implemented for: {installer_arch_os}")
136
139
  else:
137
140
  assert repo_url.startswith("https://github.com/"), f"repoURL must be a GitHub URL, got {repo_url}"
138
- downloaded, version_to_be_installed = self.download(version=version)
139
- if str(downloaded).endswith(".deb"):
140
- print(f"📦 Installing .deb package: {downloaded}")
141
- assert platform.system() == "Linux"
142
- result = subprocess.run(f"sudo nala install -y {downloaded}", shell=True, capture_output=True, text=True)
143
- success = result.returncode == 0 and result.stderr == ""
144
- if not success:
145
- desc = "Installing .deb"
146
- print(f"❌ {desc} failed")
147
- if result.stdout:
148
- print(f"STDOUT: {result.stdout}")
149
- if result.stderr:
150
- print(f"STDERR: {result.stderr}")
151
- print(f"Return code: {result.returncode}")
152
- print("🗑️ Cleaning up .deb package...")
153
- downloaded.delete(sure=True)
141
+ downloaded, version_to_be_installed = self.binary_download(version=version)
142
+ if str(downloaded).endswith(".deb"): install_deb_package(downloaded)
154
143
  else:
155
144
  if platform.system() == "Windows":
156
- 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")
157
146
  elif platform.system() in ["Linux", "Darwin"]:
158
147
  system_name = "Linux" if platform.system() == "Linux" else "macOS"
159
148
  print(f"🐧 Installing on {system_name}...")
@@ -173,13 +162,13 @@ class Installer:
173
162
  exe.with_name(name=new_exe_name, inplace=True, overwrite=True)
174
163
  INSTALL_VERSION_ROOT.joinpath(exe_name).parent.mkdir(parents=True, exist_ok=True)
175
164
  INSTALL_VERSION_ROOT.joinpath(exe_name).write_text(version_to_be_installed or "unknown", encoding="utf-8")
176
- def download(self, version: Optional[str]) -> tuple[PathExtended, str]:
165
+ def binary_download(self, version: Optional[str]) -> tuple[PathExtended, str]:
177
166
  exe_name = self._get_exe_name()
178
167
  repo_url = self.installer_data["repoURL"]
179
168
  # app_name = self.installer_data["appName"]
180
169
  download_link: Optional[str] = None
181
170
  version_to_be_installed: Optional[str] = None
182
- if "github" not in repo_url or ".zip" in repo_url or ".tar.gz" in repo_url:
171
+ if "github" not in repo_url:
183
172
  # Direct download URL
184
173
  download_link = repo_url
185
174
  version_to_be_installed = "predefined_url"
@@ -193,63 +182,17 @@ class Installer:
193
182
  print(f"🧭 Detected system={os_name} arch={arch}")
194
183
  # Use existing get_github_release method to get download link and version
195
184
  download_link, version_to_be_installed = self.get_github_release(repo_url, version)
185
+ # print(f"🌟 Retrieved download link from GitHub: {download_link}")
186
+ # print(f"📦 Version to be installed: {version_to_be_installed}")
196
187
  if download_link is None:
197
188
  raise ValueError(f"Could not retrieve download link for {exe_name} version {version or 'latest'}")
198
189
  print(f"📦 Version to be installed: {version_to_be_installed}")
199
190
  print(f"🔗 Download URL: {download_link}")
200
191
  assert download_link is not None, "download_link must be set"
201
192
  assert version_to_be_installed is not None, "version_to_be_installed must be set"
202
- downloaded = PathExtended(download_link).download(folder=INSTALL_TMP_DIR).decompress()
193
+ downloaded = download_and_prepare(download_link)
203
194
  return downloaded, version_to_be_installed
204
195
 
205
- # --------------------------- Arch / template helpers ---------------------------
206
-
207
- @staticmethod
208
- def _get_repo_name_from_url(repo_url: str) -> str:
209
- """Extract owner/repo from GitHub URL."""
210
- try:
211
- parsed = urlparse(repo_url)
212
- path_parts = parsed.path.strip("/").split("/")
213
- return f"{path_parts[0]}/{path_parts[1]}"
214
- except (IndexError, AttributeError):
215
- return ""
216
-
217
- @staticmethod
218
- def _fetch_github_release_data(repo_name: str, version: Optional[str] = None) -> Optional[dict[str, Any]]:
219
- """Fetch release data from GitHub API using requests."""
220
- import requests
221
-
222
- try:
223
- if version and version.lower() != "latest":
224
- # Fetch specific version
225
- url = f"https://api.github.com/repos/{repo_name}/releases/tags/{version}"
226
- else:
227
- # Fetch latest release
228
- url = f"https://api.github.com/repos/{repo_name}/releases/latest"
229
-
230
- response = requests.get(url, timeout=30)
231
-
232
- if response.status_code != 200:
233
- print(f"❌ Failed to fetch data for {repo_name}: HTTP {response.status_code}")
234
- return None
235
-
236
- response_data = response.json()
237
-
238
- # Check if API returned an error
239
- if "message" in response_data:
240
- if "API rate limit exceeded" in response_data.get("message", ""):
241
- print(f"🚫 Rate limit exceeded for {repo_name}")
242
- return None
243
- elif "Not Found" in response_data.get("message", ""):
244
- print(f"🔍 No releases found for {repo_name}")
245
- return None
246
-
247
- return response_data
248
-
249
- except (requests.RequestException, requests.Timeout, json.JSONDecodeError) as e:
250
- print(f"❌ Error fetching {repo_name}: {e}")
251
- return None
252
-
253
196
  def get_github_release(self, repo_url: str, version: Optional[str]) -> tuple[Optional[str], Optional[str]]:
254
197
  """
255
198
  Get download link and version from GitHub release based on fileNamePattern.
@@ -260,20 +203,20 @@ class Installer:
260
203
  filename_pattern = self.installer_data["fileNamePattern"][arch][os_name]
261
204
  if filename_pattern is None:
262
205
  raise ValueError(f"No fileNamePattern for {self._get_exe_name()} on {os_name} {arch}")
263
- repo_name = self._get_repo_name_from_url(repo_url)
264
- if not repo_name:
206
+ repo_info = get_repo_name_from_url(repo_url)
207
+ if not repo_info:
265
208
  print(f"❌ Invalid repository URL: {repo_url}")
266
209
  return None, None
267
- release_data = self._fetch_github_release_data(repo_name, version)
268
- if not release_data:
210
+ username, repository = repo_info
211
+ release_info = get_release_info(username, repository, version)
212
+ if not release_info:
269
213
  return None, None
270
- # print(release_data)
271
- actual_version = release_data.get("tag_name", "unknown")
214
+ actual_version = release_info.get("tag_name", "unknown") or "unknown"
272
215
  filename = filename_pattern.format(version=actual_version)
273
216
 
274
217
  available_filenames: list[str] = []
275
- for asset in release_data.get("assets", []):
276
- an_dl = asset.get("browser_download_url", "NA")
218
+ for asset in release_info["assets"]:
219
+ an_dl = asset["browser_download_url"]
277
220
  available_filenames.append(an_dl.split("/")[-1])
278
221
  if filename not in available_filenames:
279
222
  candidates = [
@@ -0,0 +1,175 @@
1
+ """Devops Devapps Install
2
+
3
+
4
+ sudo apt update && sudo apt install -y \
5
+ git gcc g++ clang \
6
+ yasm nasm pkg-config \
7
+ meson ninja-build \
8
+ autoconf automake libtool \
9
+ libx11-dev libxext-dev libxrandr-dev libxrender-dev libxss-dev \
10
+ libvdpau-dev libgl1-mesa-dev libegl1-mesa-dev libxv-dev \
11
+ libasound2-dev libpulse-dev \
12
+ libfribidi-dev libfreetype-dev libfontconfig1-dev libharfbuzz-dev \
13
+ libjpeg-dev libssl-dev zlib1g-dev python3-pip
14
+
15
+
16
+ """
17
+
18
+ from machineconfig.utils.installer_utils.installer_helper import get_group_name_to_repr
19
+ import typer
20
+ from typing import Annotated, Optional
21
+
22
+
23
+
24
+ def main_installer_cli(
25
+ which: Annotated[Optional[str], typer.Argument(..., help="Comma-separated list of program/groups names to install (if --group flag is set).")] = None,
26
+ group: Annotated[bool, typer.Option(..., "--group", "-g", help="Treat 'which' as a group name. A group is bundle of apps.")] = False,
27
+ interactive: Annotated[bool, typer.Option(..., "--interactive", "-i", help="Interactive selection of programs to install.")] = False,
28
+ ) -> None:
29
+ if interactive:
30
+ return install_interactively()
31
+ if which is not None:
32
+ if group:
33
+ for a_group in [x.strip() for x in which.split(",") if x.strip() != ""]:
34
+ return install_group(package_group=a_group)
35
+ else:
36
+ return install_clis(clis_names=[x.strip() for x in which.split(",") if x.strip() != ""])
37
+ else:
38
+ if group:
39
+ from rich.console import Console
40
+ from rich.table import Table
41
+ console = Console()
42
+
43
+ typer.echo("❌ You must provide a group name when using the --group/-g option.")
44
+ from machineconfig.utils.installer_utils.installer_helper import get_group_name_to_repr
45
+ res = get_group_name_to_repr()
46
+ console.print("[bold blue]Here are the available groups:[/bold blue]")
47
+ table = Table(show_header=True, header_style="bold magenta")
48
+ table.add_column("Group", style="cyan", no_wrap=True)
49
+ table.add_column("AppsBundled", style="green", overflow="fold")
50
+ for display, group_name in res.items():
51
+ # Parse display
52
+ if " -- " in display:
53
+ group_part, items_part = display.split(" -- ", 1)
54
+ group_name_parsed = group_part.replace("📦 ", "").strip()
55
+ items_str = items_part.strip()
56
+ else:
57
+ group_name_parsed = display
58
+ items_str = group_name
59
+ table.add_row(group_name_parsed, items_str)
60
+ console.print(table)
61
+ raise typer.Exit(1)
62
+ typer.echo("❌ You must provide either a program name/group name, or use --interactive/-ia option.")
63
+ import click
64
+ ctx = click.get_current_context()
65
+ typer.echo(ctx.get_help())
66
+ raise typer.Exit(1)
67
+
68
+
69
+
70
+
71
+
72
+ def install_interactively():
73
+ from machineconfig.utils.options import choose_from_options
74
+ from machineconfig.utils.schemas.installer.installer_types import get_normalized_arch, get_os_name
75
+ from machineconfig.utils.installer_utils.installer_runner import get_installers
76
+ from machineconfig.utils.installer_utils.installer_class import Installer
77
+ from rich.console import Console
78
+ from rich.panel import Panel
79
+ # from rich.table import Table
80
+ installers = get_installers(os=get_os_name(), arch=get_normalized_arch(), which_cats=None)
81
+ installer_options = [Installer(installer_data=x).get_description() for x in installers]
82
+ category_display_to_name = get_group_name_to_repr()
83
+ options = list(category_display_to_name.keys()) + installer_options
84
+ program_names = choose_from_options(multi=True, msg="Categories are prefixed with 📦", options=options, header="🚀 CHOOSE DEV APP OR CATEGORY", tv=True)
85
+ installation_messages: list[str] = []
86
+ for _an_idx, a_program_name in enumerate(program_names):
87
+ if a_program_name.startswith("📦 "):
88
+ category_name = category_display_to_name.get(a_program_name)
89
+ if category_name:
90
+ install_group(package_group=category_name)
91
+ else:
92
+ installer_idx = installer_options.index(a_program_name)
93
+ an_installer_data = installers[installer_idx]
94
+ status_message = Installer(an_installer_data).install_robust(version=None) # finish the task - this returns a status message, not a command
95
+ installation_messages.append(status_message)
96
+ if installation_messages:
97
+ console = Console()
98
+
99
+ 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))
100
+ console.print(panel)
101
+
102
+
103
+ def install_group(package_group: str):
104
+ from machineconfig.utils.installer_utils.installer_runner import get_installers, install_bulk
105
+ from machineconfig.utils.schemas.installer.installer_types import get_normalized_arch, get_os_name
106
+ from rich.console import Console
107
+ from rich.panel import Panel
108
+ # from rich.table import Table
109
+ from machineconfig.jobs.installer.package_groups import PACKAGE_GROUP2NAMES
110
+ if package_group in PACKAGE_GROUP2NAMES:
111
+ 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))
112
+ console = Console()
113
+ console.print(panel)
114
+ installers_ = get_installers(os=get_os_name(), arch=get_normalized_arch(), which_cats=[package_group])
115
+ install_bulk(installers_data=installers_)
116
+ return
117
+ console = Console()
118
+ console.print(f"❌ ERROR: Unknown package group: {package_group}. Available groups are: {list(PACKAGE_GROUP2NAMES.keys())}")
119
+
120
+
121
+ def install_clis(clis_names: list[str]):
122
+ from machineconfig.utils.schemas.installer.installer_types import get_normalized_arch, get_os_name
123
+ from machineconfig.utils.installer_utils.installer_runner import get_installers
124
+ from machineconfig.utils.installer_utils.installer_class import Installer
125
+ from rich.console import Console
126
+ all_installers_data = get_installers(os=get_os_name(), arch=get_normalized_arch(), which_cats=None)
127
+ total_messages: list[str] = []
128
+ for a_cli_name in clis_names:
129
+ if "github.com" in a_cli_name.lower():
130
+ from machineconfig.utils.installer_utils.install_from_url import install_from_github_url
131
+ install_from_github_url(github_url=a_cli_name)
132
+ continue
133
+ elif a_cli_name.startswith("https://") or a_cli_name.startswith("http://"):
134
+ print(f"⏳ Installing from binary URL: {a_cli_name} ...")
135
+ from machineconfig.utils.installer_utils.install_from_url import install_from_binary_url
136
+ install_from_binary_url(binary_url=a_cli_name)
137
+ continue
138
+ selected_installer = None
139
+ for installer in all_installers_data:
140
+ app_name = installer["appName"]
141
+ if app_name.lower() == a_cli_name.lower():
142
+ selected_installer = installer
143
+ break
144
+ if selected_installer is None:
145
+ from machineconfig.utils.installer_utils.installer_helper import handle_installer_not_found
146
+ handle_installer_not_found(a_cli_name, all_installers_data)
147
+ return None
148
+ message = Installer(selected_installer).install_robust(version=None) # finish the task
149
+ total_messages.append(message)
150
+ if total_messages:
151
+ console = Console()
152
+ console.print("\n[bold green]📊 Installation Results:[/bold green]")
153
+ for a_message in total_messages:
154
+ console.print(f"[blue]• {a_message}[/blue]")
155
+ return None
156
+ def install_if_missing(which: str) -> bool:
157
+ from machineconfig.utils.installer_utils.installer_locator_utils import check_tool_exists
158
+ exists = check_tool_exists(which)
159
+ if exists:
160
+ print(f"✅ {which} is already installed.")
161
+ return True
162
+ print(f"⏳ {which} not found. Installing...")
163
+ from machineconfig.utils.installer_utils.installer_cli import main_installer_cli
164
+ try:
165
+ main_installer_cli(which=which, interactive=False)
166
+ return True
167
+ except Exception as e:
168
+ print(f"❌ Error installing {which}: {e}")
169
+ return False
170
+
171
+ if __name__ == "__main__":
172
+ from machineconfig.utils.schemas.installer.installer_types import InstallerData
173
+ from machineconfig.utils.installer_utils.installer_class import Installer
174
+ _ = InstallerData, Installer
175
+ pass