machineconfig 5.15__py3-none-any.whl → 7.66__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 (389) 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 +0 -1
  5. machineconfig/cluster/sessions_managers/{utils → helpers}/enhanced_command_runner.py +4 -6
  6. machineconfig/cluster/sessions_managers/utils/load_balancer.py +1 -1
  7. machineconfig/cluster/sessions_managers/utils/maker.py +69 -0
  8. machineconfig/cluster/sessions_managers/wt_local.py +114 -289
  9. machineconfig/cluster/sessions_managers/wt_local_manager.py +50 -193
  10. machineconfig/cluster/sessions_managers/wt_remote.py +51 -43
  11. machineconfig/cluster/sessions_managers/wt_remote_manager.py +49 -197
  12. machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +6 -19
  13. machineconfig/cluster/sessions_managers/wt_utils/manager_persistence.py +52 -0
  14. machineconfig/cluster/sessions_managers/wt_utils/monitoring_helpers.py +50 -0
  15. machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +4 -2
  16. machineconfig/cluster/sessions_managers/wt_utils/status_reporting.py +76 -0
  17. machineconfig/cluster/sessions_managers/wt_utils/wt_helpers.py +199 -0
  18. machineconfig/cluster/sessions_managers/zellij_local.py +81 -375
  19. machineconfig/cluster/sessions_managers/zellij_local_manager.py +22 -169
  20. machineconfig/cluster/sessions_managers/zellij_remote.py +40 -41
  21. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +13 -10
  22. machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +4 -8
  23. machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +5 -20
  24. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +3 -9
  25. machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +3 -1
  26. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_helper.py +298 -0
  27. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_helper_restart.py +77 -0
  28. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_helper_with_panes.py +228 -0
  29. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_manager_helper.py +165 -0
  30. machineconfig/jobs/{python → installer}/check_installations.py +2 -3
  31. machineconfig/jobs/installer/custom/boxes.py +61 -0
  32. machineconfig/jobs/installer/custom/hx.py +76 -19
  33. machineconfig/jobs/installer/custom_dev/alacritty.py +4 -4
  34. machineconfig/jobs/installer/custom_dev/brave.py +1 -7
  35. machineconfig/jobs/installer/custom_dev/cloudflare_warp_cli.py +23 -0
  36. machineconfig/jobs/installer/custom_dev/code.py +4 -1
  37. machineconfig/jobs/installer/custom_dev/dubdb_adbc.py +30 -0
  38. machineconfig/jobs/installer/custom_dev/nerfont_windows_helper.py +9 -18
  39. machineconfig/jobs/installer/custom_dev/sysabc.py +119 -0
  40. machineconfig/jobs/installer/custom_dev/wezterm.py +2 -19
  41. machineconfig/jobs/installer/installer_data.json +1101 -115
  42. machineconfig/jobs/installer/linux_scripts/brave.sh +4 -14
  43. machineconfig/jobs/installer/linux_scripts/{warp-cli.sh → cloudflare_warp_cli.sh} +5 -17
  44. machineconfig/jobs/installer/linux_scripts/docker.sh +5 -17
  45. machineconfig/jobs/installer/linux_scripts/docker_start.sh +6 -14
  46. machineconfig/jobs/installer/linux_scripts/edge.sh +3 -11
  47. machineconfig/jobs/{linux/msc → installer/linux_scripts}/lid.sh +2 -8
  48. machineconfig/jobs/installer/linux_scripts/nerdfont.sh +5 -17
  49. machineconfig/jobs/{linux/msc → installer/linux_scripts}/network.sh +2 -8
  50. machineconfig/jobs/installer/linux_scripts/q.sh +1 -0
  51. machineconfig/jobs/installer/linux_scripts/redis.sh +6 -17
  52. machineconfig/jobs/installer/linux_scripts/vscode.sh +5 -17
  53. machineconfig/jobs/installer/linux_scripts/wezterm.sh +4 -12
  54. machineconfig/jobs/installer/package_groups.py +108 -180
  55. machineconfig/logger.py +0 -1
  56. machineconfig/profile/backup.toml +49 -0
  57. machineconfig/profile/bash_shell_profiles.md +11 -0
  58. machineconfig/profile/create_helper.py +74 -0
  59. machineconfig/profile/create_links.py +288 -0
  60. machineconfig/profile/create_links_export.py +100 -0
  61. machineconfig/profile/create_shell_profile.py +136 -0
  62. machineconfig/profile/mapper.toml +258 -0
  63. machineconfig/scripts/Restore-ThunderbirdProfile.ps1 +92 -0
  64. machineconfig/scripts/__init__.py +0 -4
  65. machineconfig/scripts/linux/{share_cloud.sh → other/share_cloud.sh} +14 -25
  66. machineconfig/scripts/linux/wrap_mcfg +47 -0
  67. machineconfig/scripts/nu/wrap_mcfg.nu +69 -0
  68. machineconfig/scripts/python/agents.py +92 -103
  69. machineconfig/scripts/python/ai/command_runner/command_runner.sh +9 -0
  70. machineconfig/scripts/python/ai/command_runner/prompt.txt +9 -0
  71. machineconfig/scripts/python/ai/generate_files.py +307 -42
  72. machineconfig/scripts/python/ai/initai.py +3 -28
  73. machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +17 -18
  74. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +17 -18
  75. machineconfig/scripts/python/ai/solutions/_shared.py +9 -1
  76. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +1 -1
  77. machineconfig/scripts/python/ai/solutions/copilot/prompts/pyright_fix.md +16 -0
  78. machineconfig/scripts/python/ai/solutions/generic.py +27 -4
  79. machineconfig/scripts/python/ai/vscode_tasks.py +37 -0
  80. machineconfig/scripts/python/cloud.py +29 -0
  81. machineconfig/scripts/python/croshell.py +111 -114
  82. machineconfig/scripts/python/define.py +31 -0
  83. machineconfig/scripts/python/devops.py +44 -103
  84. machineconfig/scripts/python/devops_navigator.py +10 -0
  85. machineconfig/scripts/python/env_manager/__init__.py +1 -0
  86. machineconfig/scripts/python/env_manager/path_manager_backend.py +47 -0
  87. machineconfig/scripts/python/env_manager/path_manager_tui.py +228 -0
  88. machineconfig/scripts/python/explore.py +49 -0
  89. machineconfig/scripts/python/fire_jobs.py +115 -152
  90. machineconfig/scripts/python/ftpx.py +29 -24
  91. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.json +14 -0
  92. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.py +37 -0
  93. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_cursor_agents.py +22 -0
  94. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_gemini.py +42 -0
  95. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_qwen.py +30 -0
  96. machineconfig/scripts/python/{fire_agents_help_launch.py → helpers_agents/fire_agents_help_launch.py} +34 -44
  97. machineconfig/scripts/python/helpers_agents/fire_agents_helper_types.py +34 -0
  98. machineconfig/scripts/python/helpers_agents/templates/prompt.txt +6 -0
  99. machineconfig/scripts/python/helpers_agents/templates/template.ps1 +14 -0
  100. machineconfig/scripts/python/helpers_agents/templates/template.sh +24 -0
  101. machineconfig/scripts/python/{cloud_copy.py → helpers_cloud/cloud_copy.py} +30 -23
  102. machineconfig/scripts/python/{cloud_mount.py → helpers_cloud/cloud_mount.py} +10 -18
  103. machineconfig/scripts/python/{cloud_sync.py → helpers_cloud/cloud_sync.py} +12 -18
  104. machineconfig/scripts/python/{helpers → helpers_cloud}/helpers2.py +1 -1
  105. machineconfig/scripts/python/helpers_croshell/crosh.py +39 -0
  106. machineconfig/scripts/python/{start_slidev.py → helpers_croshell/start_slidev.py} +2 -2
  107. machineconfig/scripts/python/helpers_devops/cli_config.py +95 -0
  108. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +89 -0
  109. machineconfig/scripts/python/helpers_devops/cli_data.py +25 -0
  110. machineconfig/scripts/python/helpers_devops/cli_nw.py +134 -0
  111. machineconfig/scripts/python/helpers_devops/cli_repos.py +182 -0
  112. machineconfig/scripts/python/helpers_devops/cli_self.py +134 -0
  113. machineconfig/scripts/python/helpers_devops/cli_share_file.py +137 -0
  114. machineconfig/scripts/python/helpers_devops/cli_share_server.py +141 -0
  115. machineconfig/scripts/python/{share_terminal.py → helpers_devops/cli_terminal.py} +35 -23
  116. machineconfig/scripts/python/helpers_devops/cli_utils.py +96 -0
  117. machineconfig/scripts/python/{devops_backup_retrieve.py → helpers_devops/devops_backup_retrieve.py} +7 -10
  118. machineconfig/scripts/python/helpers_devops/devops_status.py +511 -0
  119. machineconfig/scripts/python/{devops_update_repos.py → helpers_devops/devops_update_repos.py} +68 -49
  120. machineconfig/scripts/python/helpers_devops/themes/choose_pwsh_theme.ps1 +81 -0
  121. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +3 -0
  122. machineconfig/scripts/python/{choose_wezterm_theme.py → helpers_devops/themes/choose_wezterm_theme.py} +2 -2
  123. machineconfig/scripts/python/helpers_fire_command/__init__.py +0 -0
  124. machineconfig/scripts/python/{helpers/helpers4.py → helpers_fire_command/file_wrangler.py} +56 -20
  125. machineconfig/scripts/python/{fire_jobs_args_helper.py → helpers_fire_command/fire_jobs_args_helper.py} +5 -1
  126. machineconfig/scripts/python/{fire_jobs_route_helper.py → helpers_fire_command/fire_jobs_route_helper.py} +47 -2
  127. machineconfig/scripts/python/helpers_fire_command/fire_jobs_streamlit_helper.py +0 -0
  128. machineconfig/scripts/python/helpers_msearch/__init__.py +5 -0
  129. machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/fzfag +1 -1
  130. machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/fzfg +1 -1
  131. machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/fzfrga +1 -1
  132. machineconfig/scripts/python/helpers_navigator/__init__.py +20 -0
  133. machineconfig/scripts/python/helpers_navigator/command_builder.py +111 -0
  134. machineconfig/scripts/python/helpers_navigator/command_detail.py +44 -0
  135. machineconfig/scripts/python/helpers_navigator/command_tree.py +588 -0
  136. machineconfig/scripts/python/helpers_navigator/data_models.py +28 -0
  137. machineconfig/scripts/python/helpers_navigator/main_app.py +272 -0
  138. machineconfig/scripts/python/helpers_navigator/search_bar.py +15 -0
  139. machineconfig/scripts/python/helpers_repos/action.py +209 -0
  140. machineconfig/scripts/python/helpers_repos/action_helper.py +150 -0
  141. machineconfig/scripts/python/{repos_helper_clone.py → helpers_repos/clone.py} +2 -3
  142. machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +218 -0
  143. machineconfig/scripts/python/{count_lines.py → helpers_repos/count_lines.py} +10 -10
  144. machineconfig/scripts/python/helpers_repos/count_lines_frontend.py +17 -0
  145. machineconfig/scripts/python/{repos_helper.py → helpers_repos/entrypoint.py} +9 -17
  146. machineconfig/scripts/python/helpers_repos/grource.py +340 -0
  147. machineconfig/scripts/python/{repos_helper_record.py → helpers_repos/record.py} +4 -3
  148. machineconfig/scripts/python/helpers_repos/sync.py +66 -0
  149. machineconfig/scripts/python/{repos_helper_update.py → helpers_repos/update.py} +3 -3
  150. machineconfig/scripts/python/helpers_sessions/__init__.py +0 -0
  151. machineconfig/scripts/python/helpers_sessions/sessions_multiprocess.py +58 -0
  152. machineconfig/scripts/python/helpers_utils/download.py +152 -0
  153. machineconfig/scripts/python/helpers_utils/path.py +108 -0
  154. machineconfig/scripts/python/interactive.py +64 -84
  155. machineconfig/scripts/python/machineconfig.py +63 -0
  156. machineconfig/scripts/python/msearch.py +21 -0
  157. machineconfig/scripts/python/nw/__init__.py +0 -0
  158. machineconfig/scripts/python/{devops_add_identity.py → nw/devops_add_identity.py} +0 -2
  159. machineconfig/scripts/python/{devops_add_ssh_key.py → nw/devops_add_ssh_key.py} +73 -43
  160. machineconfig/scripts/{linux → python/nw}/mount_nfs +1 -1
  161. machineconfig/scripts/python/{mount_nfs.py → nw/mount_nfs.py} +3 -3
  162. machineconfig/scripts/{linux → python/nw}/mount_nw_drive +1 -2
  163. machineconfig/scripts/python/{mount_ssh.py → nw/mount_ssh.py} +3 -3
  164. machineconfig/scripts/python/{onetimeshare.py → nw/onetimeshare.py} +0 -1
  165. machineconfig/scripts/python/nw/ssh_debug_linux.py +391 -0
  166. machineconfig/scripts/python/nw/ssh_debug_windows.py +338 -0
  167. machineconfig/scripts/python/{wifi_conn.py → nw/wifi_conn.py} +1 -53
  168. machineconfig/scripts/python/{wsl_windows_transfer.py → nw/wsl_windows_transfer.py} +5 -4
  169. machineconfig/scripts/python/sessions.py +64 -44
  170. machineconfig/scripts/python/terminal.py +127 -0
  171. machineconfig/scripts/python/utils.py +66 -0
  172. machineconfig/scripts/windows/{mount_nfs.ps1 → mounts/mount_nfs.ps1} +1 -3
  173. machineconfig/scripts/windows/{mount_ssh.ps1 → mounts/mount_ssh.ps1} +1 -1
  174. machineconfig/scripts/windows/{share_smb.ps1 → mounts/share_smb.ps1} +0 -6
  175. machineconfig/scripts/windows/wrap_mcfg.ps1 +60 -0
  176. machineconfig/settings/broot/br.sh +0 -4
  177. machineconfig/settings/broot/conf.toml +1 -1
  178. machineconfig/settings/helix/config.toml +16 -0
  179. machineconfig/settings/helix/languages.toml +13 -4
  180. machineconfig/settings/helix/yazi-picker.sh +12 -0
  181. machineconfig/settings/lf/linux/exe/lfcd.sh +1 -0
  182. machineconfig/settings/lf/linux/exe/previewer.sh +9 -3
  183. machineconfig/settings/lf/linux/lfrc +10 -12
  184. machineconfig/settings/lf/windows/fzf_edit.ps1 +2 -2
  185. machineconfig/settings/lf/windows/lfrc +18 -38
  186. machineconfig/settings/lf/windows/mkfile.ps1 +1 -1
  187. machineconfig/settings/linters/.ruff.toml +1 -1
  188. machineconfig/settings/lvim/windows/archive/config_additional.lua +0 -6
  189. machineconfig/settings/marimo/marimo.toml +80 -0
  190. machineconfig/settings/marimo/snippets/globalize.py +34 -0
  191. machineconfig/settings/pistol/pistol.conf +1 -1
  192. machineconfig/settings/shells/bash/init.sh +55 -31
  193. machineconfig/settings/shells/nushell/config.nu +1 -34
  194. machineconfig/settings/shells/nushell/init.nu +127 -0
  195. machineconfig/settings/shells/pwsh/init.ps1 +60 -43
  196. machineconfig/settings/shells/starship/starship.toml +16 -0
  197. machineconfig/settings/shells/wezterm/wezterm.lua +2 -0
  198. machineconfig/settings/shells/wt/settings.json +32 -17
  199. machineconfig/settings/shells/zsh/init.sh +89 -0
  200. machineconfig/settings/svim/linux/init.toml +0 -4
  201. machineconfig/settings/svim/windows/init.toml +0 -3
  202. machineconfig/settings/yazi/init.lua +57 -0
  203. machineconfig/settings/yazi/keymap_linux.toml +79 -0
  204. machineconfig/settings/yazi/keymap_windows.toml +78 -0
  205. machineconfig/settings/yazi/shell/yazi_cd.ps1 +33 -0
  206. machineconfig/settings/yazi/shell/yazi_cd.sh +8 -0
  207. machineconfig/settings/yazi/yazi.toml +13 -0
  208. machineconfig/setup_linux/__init__.py +10 -0
  209. machineconfig/setup_linux/apps_desktop.sh +89 -0
  210. machineconfig/setup_linux/apps_gui.sh +64 -0
  211. machineconfig/setup_linux/{nix → others}/cli_installation.sh +9 -29
  212. machineconfig/setup_linux/ssh/openssh_all.sh +25 -0
  213. machineconfig/setup_linux/ssh/openssh_wsl.sh +38 -0
  214. machineconfig/setup_linux/uv.sh +15 -0
  215. machineconfig/setup_linux/web_shortcuts/interactive.sh +26 -6
  216. machineconfig/setup_mac/__init__.py +16 -0
  217. machineconfig/setup_mac/apps_gui.sh +248 -0
  218. machineconfig/setup_mac/ssh/openssh_setup.sh +114 -0
  219. machineconfig/setup_mac/uv.sh +36 -0
  220. machineconfig/setup_windows/__init__.py +8 -0
  221. machineconfig/setup_windows/others/power_options.ps1 +7 -0
  222. machineconfig/setup_windows/ssh/add-sshkey.ps1 +29 -0
  223. machineconfig/setup_windows/ssh/add_identity.ps1 +11 -0
  224. machineconfig/setup_windows/ssh/openssh-server.ps1 +37 -0
  225. machineconfig/setup_windows/uv.ps1 +10 -0
  226. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +27 -10
  227. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +16 -0
  228. machineconfig/utils/accessories.py +7 -5
  229. machineconfig/utils/cloud/onedrive/README.md +139 -0
  230. machineconfig/utils/code.py +133 -106
  231. machineconfig/utils/files/art/fat_croco.txt +10 -0
  232. machineconfig/utils/files/art/halfwit_croco.txt +9 -0
  233. machineconfig/utils/files/art/happy_croco.txt +22 -0
  234. machineconfig/utils/files/art/water_croco.txt +11 -0
  235. machineconfig/utils/files/ascii_art.py +1 -1
  236. machineconfig/utils/files/dbms.py +257 -0
  237. machineconfig/utils/files/headers.py +11 -14
  238. machineconfig/utils/files/ouch/__init__.py +0 -0
  239. machineconfig/utils/files/ouch/decompress.py +45 -0
  240. machineconfig/utils/files/read.py +10 -18
  241. machineconfig/utils/installer_utils/installer_class.py +68 -126
  242. machineconfig/utils/installer_utils/{installer.py → installer_cli.py} +109 -117
  243. machineconfig/utils/installer_utils/{installer_abc.py → installer_locator_utils.py} +31 -81
  244. machineconfig/utils/{installer.py → installer_utils/installer_runner.py} +44 -74
  245. machineconfig/utils/io.py +77 -23
  246. machineconfig/utils/links.py +254 -162
  247. machineconfig/utils/meta.py +255 -0
  248. machineconfig/utils/notifications.py +1 -1
  249. machineconfig/utils/options.py +13 -3
  250. machineconfig/utils/path_extended.py +46 -100
  251. machineconfig/utils/path_helper.py +75 -22
  252. machineconfig/utils/procs.py +50 -70
  253. machineconfig/utils/scheduler.py +94 -97
  254. machineconfig/utils/scheduling.py +0 -3
  255. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
  256. machineconfig/utils/schemas/layouts/layout_types.py +1 -1
  257. machineconfig/utils/source_of_truth.py +3 -6
  258. machineconfig/utils/ssh.py +742 -264
  259. machineconfig/utils/ssh_utils/utils.py +0 -0
  260. machineconfig/utils/terminal.py +2 -113
  261. machineconfig/utils/tst.py +20 -0
  262. machineconfig/utils/upgrade_packages.py +109 -28
  263. machineconfig/utils/ve.py +11 -4
  264. machineconfig-7.66.dist-info/METADATA +124 -0
  265. machineconfig-7.66.dist-info/RECORD +451 -0
  266. machineconfig-7.66.dist-info/entry_points.txt +15 -0
  267. machineconfig/cluster/sessions_managers/ffile.py +0 -4
  268. machineconfig/jobs/installer/linux_scripts/pgsql.sh +0 -49
  269. machineconfig/jobs/installer/linux_scripts/timescaledb.sh +0 -85
  270. machineconfig/jobs/linux/msc/cli_agents.sh +0 -16
  271. machineconfig/jobs/python/python_ve_symlink.py +0 -37
  272. machineconfig/jobs/python/vscode/api.py +0 -57
  273. machineconfig/jobs/python/vscode/sync_code.py +0 -73
  274. machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +0 -14
  275. machineconfig/jobs/windows/start_terminal.ps1 +0 -6
  276. machineconfig/jobs/windows/startup_file.cmd +0 -2
  277. machineconfig/profile/create.py +0 -303
  278. machineconfig/profile/shell.py +0 -176
  279. machineconfig/scripts/cloud/init.sh +0 -119
  280. machineconfig/scripts/linux/agents +0 -2
  281. machineconfig/scripts/linux/choose_wezterm_theme +0 -3
  282. machineconfig/scripts/linux/cloud_copy +0 -2
  283. machineconfig/scripts/linux/cloud_mount +0 -2
  284. machineconfig/scripts/linux/cloud_repo_sync +0 -2
  285. machineconfig/scripts/linux/cloud_sync +0 -2
  286. machineconfig/scripts/linux/croshell +0 -3
  287. machineconfig/scripts/linux/devops +0 -2
  288. machineconfig/scripts/linux/fire +0 -2
  289. machineconfig/scripts/linux/ftpx +0 -2
  290. machineconfig/scripts/linux/fzf2g +0 -21
  291. machineconfig/scripts/linux/fzffg +0 -25
  292. machineconfig/scripts/linux/gh_models +0 -2
  293. machineconfig/scripts/linux/initai +0 -2
  294. machineconfig/scripts/linux/kill_process +0 -2
  295. machineconfig/scripts/linux/scheduler +0 -2
  296. machineconfig/scripts/linux/sessions +0 -2
  297. machineconfig/scripts/linux/share_smb +0 -1
  298. machineconfig/scripts/linux/start_slidev +0 -2
  299. machineconfig/scripts/linux/start_terminals +0 -3
  300. machineconfig/scripts/linux/warp-cli.sh +0 -122
  301. machineconfig/scripts/linux/wifi_conn +0 -2
  302. machineconfig/scripts/linux/z_ls +0 -104
  303. machineconfig/scripts/python/ai/solutions/copilot/prompts/allLintersAndTypeCheckers.prompt.md +0 -5
  304. machineconfig/scripts/python/cloud_repo_sync.py +0 -190
  305. machineconfig/scripts/python/count_lines_frontend.py +0 -16
  306. machineconfig/scripts/python/dotfile.py +0 -78
  307. machineconfig/scripts/python/fire_agents_helper_types.py +0 -12
  308. machineconfig/scripts/python/get_zellij_cmd.py +0 -15
  309. machineconfig/scripts/python/gh_models.py +0 -104
  310. machineconfig/scripts/python/helpers/repo_sync_helpers.py +0 -116
  311. machineconfig/scripts/python/repos.py +0 -132
  312. machineconfig/scripts/python/repos_helper_action.py +0 -378
  313. machineconfig/scripts/python/snapshot.py +0 -25
  314. machineconfig/scripts/python/start_terminals.py +0 -121
  315. machineconfig/scripts/python/t4.py +0 -17
  316. machineconfig/scripts/windows/agents.ps1 +0 -1
  317. machineconfig/scripts/windows/choose_wezterm_theme.ps1 +0 -1
  318. machineconfig/scripts/windows/cloud_copy.ps1 +0 -1
  319. machineconfig/scripts/windows/cloud_mount.ps1 +0 -1
  320. machineconfig/scripts/windows/cloud_repo_sync.ps1 +0 -1
  321. machineconfig/scripts/windows/cloud_sync.ps1 +0 -1
  322. machineconfig/scripts/windows/croshell.ps1 +0 -1
  323. machineconfig/scripts/windows/devops.ps1 +0 -1
  324. machineconfig/scripts/windows/dotfile.ps1 +0 -1
  325. machineconfig/scripts/windows/fire.ps1 +0 -1
  326. machineconfig/scripts/windows/ftpx.ps1 +0 -1
  327. machineconfig/scripts/windows/gpt.ps1 +0 -1
  328. machineconfig/scripts/windows/grep.ps1 +0 -2
  329. machineconfig/scripts/windows/initai.ps1 +0 -1
  330. machineconfig/scripts/windows/kill_process.ps1 +0 -1
  331. machineconfig/scripts/windows/nano.ps1 +0 -3
  332. machineconfig/scripts/windows/pomodoro.ps1 +0 -1
  333. machineconfig/scripts/windows/reload_path.ps1 +0 -3
  334. machineconfig/scripts/windows/scheduler.ps1 +0 -1
  335. machineconfig/scripts/windows/sessions.ps1 +0 -1
  336. machineconfig/scripts/windows/snapshot.ps1 +0 -1
  337. machineconfig/scripts/windows/start_slidev.ps1 +0 -1
  338. machineconfig/scripts/windows/start_terminals.ps1 +0 -1
  339. machineconfig/scripts/windows/wifi_conn.ps1 +0 -2
  340. machineconfig/scripts/windows/wsl_rdp_windows_port_forwarding.ps1 +0 -46
  341. machineconfig/scripts/windows/wsl_ssh_windows_port_forwarding.ps1 +0 -76
  342. machineconfig/settings/lf/linux/exe/fzf_nano.sh +0 -16
  343. machineconfig/setup_linux/others/openssh-server_add_pub_key.sh +0 -57
  344. machineconfig/setup_linux/web_shortcuts/croshell.sh +0 -11
  345. machineconfig/setup_linux/web_shortcuts/ssh.sh +0 -52
  346. machineconfig/setup_windows/web_shortcuts/all.ps1 +0 -18
  347. machineconfig/setup_windows/web_shortcuts/ascii_art.ps1 +0 -36
  348. machineconfig/setup_windows/web_shortcuts/croshell.ps1 +0 -16
  349. machineconfig/setup_windows/web_shortcuts/ssh.ps1 +0 -11
  350. machineconfig/utils/ai/generate_file_checklist.py +0 -68
  351. machineconfig-5.15.dist-info/METADATA +0 -188
  352. machineconfig-5.15.dist-info/RECORD +0 -415
  353. machineconfig-5.15.dist-info/entry_points.txt +0 -18
  354. machineconfig/cluster/sessions_managers/{utils → helpers}/load_balancer_helper.py +0 -0
  355. machineconfig/scripts/linux/{share_nfs → other/share_nfs} +0 -0
  356. machineconfig/scripts/linux/{start_docker → other/start_docker} +0 -0
  357. machineconfig/scripts/linux/{switch_ip → other/switch_ip} +0 -0
  358. machineconfig/{jobs/python → scripts/python/helpers_agents}/__init__.py +0 -0
  359. machineconfig/scripts/python/{helpers → helpers_agents/agentic_frameworks}/__init__.py +0 -0
  360. machineconfig/scripts/python/{fire_agents_help_search.py → helpers_agents/fire_agents_help_search.py} +0 -0
  361. machineconfig/scripts/python/{fire_agents_load_balancer.py → helpers_agents/fire_agents_load_balancer.py} +0 -0
  362. machineconfig/{jobs/windows/msc/cli_agents.bat → scripts/python/helpers_cloud/__init__.py} +0 -0
  363. machineconfig/scripts/python/{helpers → helpers_cloud}/cloud_helpers.py +1 -1
  364. /machineconfig/scripts/python/{helpers → helpers_cloud}/helpers5.py +0 -0
  365. /machineconfig/{jobs/windows/msc/cli_agents.ps1 → scripts/python/helpers_croshell/__init__.py} +0 -0
  366. /machineconfig/scripts/python/{pomodoro.py → helpers_croshell/pomodoro.py} +0 -0
  367. /machineconfig/scripts/python/{scheduler.py → helpers_croshell/scheduler.py} +0 -0
  368. /machineconfig/scripts/python/{viewer.py → helpers_croshell/viewer.py} +0 -0
  369. /machineconfig/scripts/python/{viewer_template.py → helpers_croshell/viewer_template.py} +0 -0
  370. /machineconfig/scripts/python/{fire_jobs_streamlit_helper.py → helpers_devops/__init__.py} +0 -0
  371. /machineconfig/scripts/{windows/share_nfs.ps1 → python/helpers_devops/themes/__init__.py} +0 -0
  372. /machineconfig/{settings/yazi/keymap.toml → scripts/python/helpers_devops/themes/choose_starship_theme.ps1} +0 -0
  373. /machineconfig/scripts/python/{cloud_manager.py → helpers_fire_command/cloud_manager.py} +0 -0
  374. /machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/skrg +0 -0
  375. /machineconfig/scripts/{windows → python/helpers_msearch/scripts_windows}/fzfb.ps1 +0 -0
  376. /machineconfig/scripts/{windows → python/helpers_msearch/scripts_windows}/fzfg.ps1 +0 -0
  377. /machineconfig/scripts/{windows → python/helpers_msearch/scripts_windows}/fzfrga.bat +0 -0
  378. /machineconfig/scripts/{linux → python/nw}/mount_drive +0 -0
  379. /machineconfig/scripts/python/{mount_nw_drive.py → nw/mount_nw_drive.py} +0 -0
  380. /machineconfig/scripts/{linux → python/nw}/mount_smb +0 -0
  381. /machineconfig/scripts/windows/{mount_nw.ps1 → mounts/mount_nw.ps1} +0 -0
  382. /machineconfig/scripts/windows/{mount_smb.ps1 → mounts/mount_smb.ps1} +0 -0
  383. /machineconfig/scripts/windows/{share_cloud.cmd → mounts/share_cloud.cmd} +0 -0
  384. /machineconfig/scripts/windows/{unlock_bitlocker.ps1 → mounts/unlock_bitlocker.ps1} +0 -0
  385. /machineconfig/setup_linux/{web_shortcuts → others}/android.sh +0 -0
  386. /machineconfig/{jobs/windows/archive → setup_windows/ssh}/openssh-server_add_key.ps1 +0 -0
  387. /machineconfig/{jobs/windows/archive → setup_windows/ssh}/openssh-server_copy-ssh-id.ps1 +0 -0
  388. {machineconfig-5.15.dist-info → machineconfig-7.66.dist-info}/WHEEL +0 -0
  389. {machineconfig-5.15.dist-info → machineconfig-7.66.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,255 @@
1
+ """Metaprogramming utilities for analyzing and serializing Python functions."""
2
+
3
+ from collections.abc import Callable
4
+ from typing import Any
5
+
6
+
7
+ def get_import_module_string(py_file: str) -> str:
8
+ from machineconfig.scripts.python.helpers_fire_command.file_wrangler import get_import_module_code
9
+ from machineconfig.utils.accessories import get_repo_root
10
+ from pathlib import Path
11
+ repo_root = get_repo_root(Path(py_file))
12
+ import_line = get_import_module_code(py_file)
13
+ if repo_root is not None:
14
+ repo_root_add = f"""sys.path.append(r'{repo_root}')"""
15
+ else:
16
+ repo_root_add = ""
17
+ txt: str = f"""
18
+ try:
19
+ {import_line}
20
+ except (ImportError, ModuleNotFoundError) as ex:
21
+ print(fr"❌ Failed to import `{py_file}` as a module: {{ex}} ")
22
+ print(fr"⚠️ Attempting import with ad-hoc `$PATH` manipulation. DO NOT pickle any objects in this session as correct deserialization cannot be guaranteed.")
23
+ import sys
24
+ sys.path.append(r'{Path(py_file).parent}')
25
+ {repo_root_add}
26
+ from {Path(py_file).stem} import *
27
+ print(fr"✅ Successfully imported `{py_file}`")
28
+ """
29
+ return txt
30
+
31
+
32
+ def lambda_to_python_script(lmb: Callable[[], Any], in_global: bool, import_module: bool) -> str:
33
+ """
34
+ caveats: always use keyword arguments in the lambda call for best results.
35
+ return statement not allowed in the wrapped function (otherwise it can be put in the global space)
36
+ type hint in kwargs has nothing that is not built in, e.g. Optional will not work as it requires an import.
37
+
38
+ Given a no-arg lambda like `lambda: func(a=var1, b=var2)`,
39
+ return a string containing the full function definition of `func`
40
+ but with the defaults for the parameters provided in the call replaced
41
+ by the *actual* values (repr) taken from the lambda's globals.
42
+
43
+ All imports are local to this function.
44
+
45
+ Args:
46
+ lmb: A lambda function with no arguments
47
+ in_global: If True, return kwargs as global variable assignments followed by dedented body.
48
+ If False, return the full function definition with updated defaults.
49
+ import_module: When True, prepend module import bootstrap code for the function's source file.
50
+ """
51
+ # local imports
52
+ import inspect as _inspect
53
+ import ast as _ast
54
+ import textwrap as _textwrap
55
+ import types as _types
56
+ from pathlib import Path as _Path
57
+
58
+ def _stringify_annotation(annotation: Any) -> Any:
59
+ if annotation is _inspect.Signature.empty or annotation is _inspect.Parameter.empty:
60
+ return annotation
61
+ if isinstance(annotation, str):
62
+ return annotation
63
+ try:
64
+ return _inspect.formatannotation(annotation)
65
+ except Exception:
66
+ return str(annotation)
67
+
68
+ # sanity checks
69
+ if not (callable(lmb) and isinstance(lmb, _types.LambdaType)):
70
+ raise TypeError("Expected a lambda function object")
71
+
72
+ src = _inspect.getsource(lmb)
73
+ src = _textwrap.dedent(src)
74
+ tree = _ast.parse(src)
75
+
76
+ # find first Lambda node
77
+ lambda_node = None
78
+ for n in _ast.walk(tree):
79
+ if isinstance(n, _ast.Lambda):
80
+ lambda_node = n
81
+ break
82
+ if lambda_node is None:
83
+ raise ValueError("Could not find a lambda expression in source")
84
+
85
+ body = lambda_node.body
86
+ if not isinstance(body, _ast.Call):
87
+ raise ValueError("Lambda body is not a call expression")
88
+
89
+ globals_dict = getattr(lmb, "__globals__", {})
90
+
91
+ # Also capture closure variables from the lambda
92
+ closure_dict: dict[str, Any] = {}
93
+ if lmb.__closure__:
94
+ code_obj = lmb.__code__
95
+ freevars = code_obj.co_freevars
96
+ for i, var_name in enumerate(freevars):
97
+ closure_dict[var_name] = lmb.__closure__[i].cell_contents
98
+
99
+ # Merge globals and closures (closures take precedence for shadowing)
100
+ eval_namespace = {**globals_dict, **closure_dict}
101
+
102
+ # resolve the function object being called
103
+ try:
104
+ func_ref_src = _ast.unparse(body.func)
105
+ except AttributeError:
106
+ func_ref_src = _ast.get_source_segment(src, body.func) or ""
107
+ try:
108
+ func_obj = eval(func_ref_src, eval_namespace)
109
+ except Exception as e:
110
+ raise RuntimeError(f"Could not resolve function reference '{func_ref_src}': {e}")
111
+
112
+ if not callable(func_obj):
113
+ raise TypeError("Resolved object is not callable")
114
+
115
+ func_name = getattr(func_obj, "__name__", "<unknown>")
116
+
117
+ import_prefix: str = ""
118
+ if import_module:
119
+ module_file = _inspect.getsourcefile(func_obj)
120
+ module_path_candidate: str = module_file if module_file is not None else _inspect.getfile(func_obj)
121
+ import_prefix = get_import_module_string(str(_Path(module_path_candidate)))
122
+
123
+ # Evaluate each keyword argument value in the lambda's globals to get real Python objects
124
+ call_kwargs: dict[str, Any] = {}
125
+ for kw in body.keywords:
126
+ if kw.arg is None:
127
+ # **kwargs in call — evaluate to dict and merge
128
+ try:
129
+ val = eval(compile(_ast.Expression(kw.value), "<lambda_eval>", "eval"), eval_namespace)
130
+ if isinstance(val, dict):
131
+ call_kwargs.update(val)
132
+ else:
133
+ raise ValueError("Keyword expansion did not evaluate to a dict")
134
+ except Exception as e:
135
+ raise RuntimeError(f"Failed to evaluate **kwargs expression: {e}")
136
+ else:
137
+ try:
138
+ val = eval(compile(_ast.Expression(kw.value), "<lambda_eval>", "eval"), eval_namespace)
139
+ call_kwargs[kw.arg] = val
140
+ except Exception as e:
141
+ raise RuntimeError(f"Failed to evaluate value for kw '{kw.arg}': {e}")
142
+
143
+ # Try to get original source and dedent it for body extraction
144
+ try:
145
+ orig_src = _inspect.getsource(func_obj)
146
+ ded = _textwrap.dedent(orig_src)
147
+ lines = ded.splitlines()
148
+ def_index = None
149
+ for i, ln in enumerate(lines):
150
+ if ln.lstrip().startswith(f"def {func_name}("):
151
+ def_index = i
152
+ break
153
+ if def_index is None:
154
+ body_lines = ded.splitlines()
155
+ else:
156
+ signature_end_index = None
157
+ for i in range(def_index, len(lines)):
158
+ line_no_comment = lines[i].split("#", 1)[0].rstrip()
159
+ if line_no_comment.endswith(":"):
160
+ signature_end_index = i
161
+ break
162
+ if signature_end_index is None:
163
+ body_lines = lines[def_index + 1 :]
164
+ else:
165
+ body_lines = lines[signature_end_index + 1 :]
166
+ # ensure we have a body, otherwise use pass
167
+ if not any(line.strip() for line in body_lines):
168
+ body_text = " pass\n"
169
+ else:
170
+ joined_body = "\n".join(body_lines)
171
+ if not joined_body.endswith("\n"):
172
+ joined_body = f"{joined_body}\n"
173
+ body_text = joined_body
174
+ except (OSError, IOError, TypeError):
175
+ body_text = " pass\n"
176
+
177
+ # Build a replaced signature using inspect.signature
178
+ sig = _inspect.signature(func_obj)
179
+ new_params: list[_inspect.Parameter] = []
180
+ for name, param in sig.parameters.items():
181
+ # If the call provided a value for this parameter, replace default
182
+ if name in call_kwargs:
183
+ new_default = call_kwargs[name]
184
+ else:
185
+ new_default = param.default
186
+
187
+ normalized_annotation = _stringify_annotation(param.annotation)
188
+
189
+ if new_default is _inspect.Parameter.empty:
190
+ new_param = _inspect.Parameter(name, param.kind, annotation=normalized_annotation)
191
+ else:
192
+ new_param = _inspect.Parameter(
193
+ name, param.kind, default=new_default, annotation=normalized_annotation
194
+ )
195
+ new_params.append(new_param)
196
+
197
+ return_annotation = _stringify_annotation(sig.return_annotation)
198
+ new_sig = _inspect.Signature(parameters=new_params, return_annotation=return_annotation)
199
+
200
+ # If in_global mode, return kwargs as global assignments + dedented body
201
+ if in_global:
202
+ global_assignments: list[str] = []
203
+ for name, param in sig.parameters.items():
204
+ # Get the value from call_kwargs if provided, else use original default
205
+ if name in call_kwargs:
206
+ value = call_kwargs[name]
207
+ elif param.default is not _inspect.Parameter.empty:
208
+ value = param.default
209
+ else:
210
+ # No value provided and no default - skip this parameter
211
+ continue
212
+
213
+ # Build type annotation string if available
214
+ if param.annotation is not _inspect.Parameter.empty:
215
+ annotation_literal = _stringify_annotation(param.annotation)
216
+ if isinstance(annotation_literal, str):
217
+ global_assignments.append(f"{name}: {repr(annotation_literal)} = {repr(value)}")
218
+ else:
219
+ global_assignments.append(f"{name} = {repr(value)}")
220
+ else:
221
+ global_assignments.append(f"{name} = {repr(value)}")
222
+
223
+ # Dedent the body text to remove function indentation
224
+ dedented_body = _textwrap.dedent(body_text).rstrip()
225
+
226
+ # Combine global assignments and body
227
+ if global_assignments:
228
+ result_parts: list[str] = ["\n".join(global_assignments), "", dedented_body]
229
+ result_text = "\n".join(result_parts)
230
+ else:
231
+ result_text = dedented_body
232
+ else:
233
+ header = f"def {func_name}{new_sig}:\n"
234
+ result_text = header + body_text
235
+
236
+ if in_global:
237
+ lines = result_text.splitlines()
238
+ if lines[-1].startswith("return "):
239
+ lines[-1] = lines[-1].replace("return ", "# return ", 1)
240
+ result_text = "\n".join(lines)
241
+
242
+ if "Optional" in result_text or "Any" in result_text or "Union" in result_text or "Literal" in result_text:
243
+ result_text = "from typing import Optional, Any, Union, Literal\n\n" + result_text
244
+ if import_prefix:
245
+ result_text = f"{import_prefix}{result_text}"
246
+ return result_text
247
+
248
+ if __name__ == "__main__":
249
+ from machineconfig.utils.code import print_code
250
+ import_code_robust = "<import_code_robust>"
251
+ res = lambda_to_python_script(
252
+ lmb=lambda: print_code(code=import_code_robust, lexer="python", desc="import as module code"),
253
+ in_global=True, import_module=False
254
+ )
255
+ print(res)
@@ -110,7 +110,7 @@ encryption = ssl
110
110
 
111
111
  def send_message(self, to: str, subject: str, body: str, txt_to_html: bool = True, attachments: Optional[list[Any]] = None):
112
112
  _ = attachments
113
- body += "\n\nThis is an automated email sent via crocodile.comms script."
113
+ body += "\n\nThis is an automated email sent via machineconfig.comms script."
114
114
  # msg = message.EmailMessage()
115
115
  msg = MIMEMultipart("alternative")
116
116
  msg["subject"] = subject
@@ -1,10 +1,17 @@
1
1
  from pathlib import Path
2
- from machineconfig.utils.installer_utils.installer_abc import check_tool_exists
2
+ from machineconfig.utils.installer_utils.installer_locator_utils import check_tool_exists
3
3
  from rich.text import Text
4
4
  from rich.panel import Panel
5
5
  from rich.console import Console
6
6
  import subprocess
7
- from typing import Optional, Union, Iterable, overload, Literal
7
+ from typing import Optional, Union, Iterable, overload, Literal, cast
8
+
9
+
10
+ # def strip_ansi_codes(text: str) -> str:
11
+ # """Remove ANSI color codes from text."""
12
+ # import re
13
+ # return re.sub(r'\x1b\[[0-9;]*[a-zA-Z]', '', text)
14
+
8
15
 
9
16
  @overload
10
17
  def choose_from_options[T](msg: str, options: Iterable[T], multi: Literal[False], custom_input: bool = False, header: str = "", tail: str = "", prompt: str = "", default: Optional[T] = None, fzf: bool = False) -> T: ...
@@ -22,17 +29,20 @@ def choose_from_options[T](msg: str, options: Iterable[T], multi: bool, custom_i
22
29
  from pyfzf.pyfzf import FzfPrompt
23
30
  fzf_prompt = FzfPrompt()
24
31
  nl = "\n"
25
- choice_string_multi: list[str] = fzf_prompt.prompt(choices=options_strings, fzf_options=("--multi" if multi else "") + f' --prompt "{prompt.replace(nl, " ")}" ') # --border-label={msg.replace(nl, ' ')}")
32
+ choice_string_multi: list[str] = fzf_prompt.prompt(choices=options_strings, fzf_options=("--multi" if multi else "") + f' --prompt "{prompt.replace(nl, " ")}" --ansi') # --border-label={msg.replace(nl, ' ')}")
26
33
  # --border=rounded doens't work on older versions of fzf installed at Ubuntu 20.04
27
34
  if not multi:
28
35
  try:
29
36
  choice_one_string = choice_string_multi[0]
37
+ if isinstance(list(options)[0], str): return cast(T, choice_one_string)
30
38
  choice_idx = options_strings.index(choice_one_string)
31
39
  return list(options)[choice_idx]
32
40
  except IndexError as ie:
33
41
  print(f"❌ Error: {options=}, {choice_string_multi=}")
34
42
  print(f"🔍 Available choices: {choice_string_multi}")
35
43
  raise ie
44
+ if isinstance(list(options)[0], str):
45
+ return cast(list[T], choice_string_multi)
36
46
  choice_idx_s = [options_strings.index(x) for x in choice_string_multi]
37
47
  return [list(options)[x] for x in choice_idx_s]
38
48
  else:
@@ -1,4 +1,5 @@
1
1
  from machineconfig.utils.accessories import randstr
2
+ from machineconfig.utils.io import decrypt, encrypt
2
3
 
3
4
  from datetime import datetime
4
5
  import time
@@ -10,10 +11,12 @@ from platform import system
10
11
  from typing import Any, Optional, Union, Callable, TypeAlias, Literal
11
12
 
12
13
 
14
+
13
15
  OPLike: TypeAlias = Union[str, "PathExtended", Path, None]
14
16
  PLike: TypeAlias = Union[str, "PathExtended", Path]
15
17
  FILE_MODE: TypeAlias = Literal["r", "w", "x", "a"]
16
18
  SHUTIL_FORMATS: TypeAlias = Literal["zip", "tar", "gztar", "bztar", "xztar"]
19
+ DECOMPRESS_SUPPORTED_FORMATS = [".tar.gz", ".tgz", ".tar", ".gz", ".tar.bz", ".tbz", ".tar.xz", ".zip", ".7z"]
17
20
 
18
21
 
19
22
  def _is_user_admin() -> bool:
@@ -54,81 +57,6 @@ def _run_shell_command(
54
57
  )
55
58
 
56
59
 
57
- def pwd2key(password: str, salt: Optional[bytes] = None, iterations: int = 10) -> bytes: # Derive a secret key from a given password and salt"""
58
- import base64
59
-
60
- if salt is None:
61
- import hashlib
62
-
63
- m = hashlib.sha256()
64
- m.update(password.encode(encoding="utf-8"))
65
- return base64.urlsafe_b64encode(s=m.digest()) # make url-safe bytes required by Ferent.
66
- from cryptography.hazmat.primitives import hashes
67
- from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
68
-
69
- return base64.urlsafe_b64encode(PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=salt, iterations=iterations, backend=None).derive(password.encode()))
70
-
71
-
72
- def encrypt(msg: bytes, key: Optional[bytes] = None, pwd: Optional[str] = None, salted: bool = True, iteration: Optional[int] = None, gen_key: bool = False) -> bytes:
73
- import base64
74
- from cryptography.fernet import Fernet
75
-
76
- salt, iteration = None, None
77
- if pwd is not None: # generate it from password
78
- assert (key is None) and (type(pwd) is str), "❌ You can either pass key or pwd, or none of them, but not both."
79
- import secrets
80
-
81
- iteration = iteration or secrets.randbelow(exclusive_upper_bound=1_000_000)
82
- salt = secrets.token_bytes(nbytes=16) if salted else None
83
- key_resolved = pwd2key(password=pwd, salt=salt, iterations=iteration)
84
- elif key is None:
85
- if gen_key:
86
- key_resolved = Fernet.generate_key()
87
- Path.home().joinpath("dotfiles/creds/data/encrypted_files_key.bytes").write_bytes(key_resolved)
88
- else:
89
- try:
90
- key_resolved = Path.home().joinpath("dotfiles/creds/data/encrypted_files_key.bytes").read_bytes()
91
- print(f"⚠️ Using key from: {Path.home().joinpath('dotfiles/creds/data/encrypted_files_key.bytes')}")
92
- except FileNotFoundError as err:
93
- print("\n" * 3, "~" * 50, """Consider Loading up your dotfiles or pass `gen_key=True` to make and save one.""", "~" * 50, "\n" * 3)
94
- raise FileNotFoundError(err) from err
95
- elif isinstance(key, (str, PathExtended, Path)):
96
- key_resolved = Path(key).read_bytes() # a path to a key file was passed, read it:
97
- elif type(key) is bytes:
98
- key_resolved = key # key passed explicitly
99
- else:
100
- raise TypeError("❌ Key must be either a path, bytes object or None.")
101
- code = Fernet(key=key_resolved).encrypt(msg)
102
- if pwd is not None and salt is not None and iteration is not None:
103
- return base64.urlsafe_b64encode(b"%b%b%b" % (salt, iteration.to_bytes(4, "big"), base64.urlsafe_b64decode(code)))
104
- return code
105
-
106
-
107
- def decrypt(token: bytes, key: Optional[bytes] = None, pwd: Optional[str] = None, salted: bool = True) -> bytes:
108
- import base64
109
-
110
- if pwd is not None:
111
- assert key is None, "❌ You can either pass key or pwd, or none of them, but not both."
112
- if salted:
113
- decoded = base64.urlsafe_b64decode(token)
114
- salt, iterations, token = decoded[:16], decoded[16:20], base64.urlsafe_b64encode(decoded[20:])
115
- key_resolved = pwd2key(password=pwd, salt=salt, iterations=int.from_bytes(bytes=iterations, byteorder="big"))
116
- else:
117
- key_resolved = pwd2key(password=pwd) # trailing `;` prevents IPython from caching the result.
118
- elif type(key) is bytes:
119
- assert pwd is None, "❌ You can either pass key or pwd, or none of them, but not both."
120
- key_resolved = key # passsed explicitly
121
- elif key is None:
122
- key_resolved = Path.home().joinpath("dotfiles/creds/data/encrypted_files_key.bytes").read_bytes() # read from file
123
- elif isinstance(key, (str, Path)):
124
- key_resolved = Path(key).read_bytes() # passed a path to a file containing kwy
125
- else:
126
- raise TypeError(f"❌ Key must be either str, P, Path, bytes or None. Recieved: {type(key)}")
127
- from cryptography.fernet import Fernet
128
-
129
- return Fernet(key=key_resolved).decrypt(token)
130
-
131
-
132
60
  def validate_name(astring: str, replace: str = "_") -> str:
133
61
  import re
134
62
 
@@ -167,7 +95,7 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
167
95
  print(f"🗑️ ❌ DELETED {repr(self)}.")
168
96
  return self
169
97
 
170
- def move(self, folder: OPLike = None, name: Optional[str] = None, path: OPLike = None, rel2it: bool = False, overwrite: bool = False, verbose: bool = True, parents: bool = True, content: bool = False) -> "PathExtended":
98
+ def move(self, folder: OPLike = None, name: Optional[str] = None, path: OPLike = None, rel2it: bool = False, overwrite: bool = False, verbose: bool = True, parents: bool = True, content: bool = False) -> "PathExtended": # type: ignore
171
99
  path = self._resolve_path(folder=folder, name=name, path=path, default_name=self.absolute().name, rel2it=rel2it)
172
100
  if parents:
173
101
  path.parent.mkdir(parents=True, exist_ok=True)
@@ -193,9 +121,7 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
193
121
  print(f"🚚 MOVED {repr(self)} ==> {repr(path)}`")
194
122
  return path
195
123
 
196
- def copy(
197
- self, folder: OPLike = None, name: Optional[str] = None, path: OPLike = None, content: bool = False, verbose: bool = True, append: Optional[str] = None, overwrite: bool = False, orig: bool = False
198
- ) -> "PathExtended": # tested %100 # TODO: replace `content` flag with ability to interpret "*" in resolve method.
124
+ def copy(self, folder: OPLike = None, name: Optional[str] = None, path: OPLike = None, content: bool = False, verbose: bool = True, append: Optional[str] = None, overwrite: bool = False, orig: bool = False) -> "PathExtended": # type: ignore
199
125
  dest = self._resolve_path(folder=folder, name=name, path=path, default_name=self.name, rel2it=False)
200
126
  dest = dest.expanduser().resolve()
201
127
  dest.parent.mkdir(parents=True, exist_ok=True)
@@ -227,7 +153,6 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
227
153
  # ======================================= File Editing / Reading ===================================
228
154
  def download(self, folder: OPLike = None, name: Optional[str] = None, allow_redirects: bool = True, timeout: Optional[int] = None, params: Any = None) -> "PathExtended":
229
155
  import requests
230
-
231
156
  response = requests.get(self.as_url_str(), allow_redirects=allow_redirects, timeout=timeout, params=params) # Alternative: from urllib import request; request.urlopen(url).read().decode('utf-8').
232
157
  assert response.status_code == 200, f"Download failed with status code {response.status_code}\n{response.text}"
233
158
  if name is not None:
@@ -555,9 +480,6 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
555
480
  **kwargs: Any,
556
481
  ) -> "PathExtended":
557
482
  path_resolved, slf = self._resolve_path(folder, name, path, self.name).expanduser().resolve(), self.expanduser().resolve()
558
- # if use_7z: # benefits over regular zip and encrypt: can handle very large files with low memory footprint
559
- # path_resolved = path_resolved + '.7z' if not path_resolved.suffix == '.7z' else path_resolved
560
- # with install_n_import("py7zr").SevenZipFile(file=path_resolved, mode=mode, password=pwd) as archive: archive.writeall(path=str(slf), arcname=None)
561
483
  arcname_obj = PathExtended(arcname or slf.name)
562
484
  if arcname_obj.name != slf.name:
563
485
  arcname_obj /= slf.name # arcname has to start from somewhere and end with filename
@@ -630,15 +552,6 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
630
552
  folder = folder if not content else folder.parent
631
553
  if slf.suffix == ".7z":
632
554
  raise NotImplementedError("I have not implemented this yet")
633
- # if overwrite: P(folder).delete(sure=True)
634
- # result = folder
635
- # import py7zr
636
- # with py7zr.SevenZipFile(file=slf, mode='r', password=pwd) as archive:
637
- # if pattern is not None:
638
- # import re
639
- # pat = re.compile(pattern)
640
- # archive.extract(path=folder, targets=[f for f in archive.getnames() if pat.match(f)])
641
- # else: archive.extractall(path=folder)
642
555
  else:
643
556
  if overwrite:
644
557
  if not content:
@@ -773,19 +686,52 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
773
686
  return ret
774
687
 
775
688
  def decompress(self, folder: OPLike = None, name: Optional[str] = None, path: OPLike = None, inplace: bool = False, orig: bool = False, verbose: bool = True) -> "PathExtended":
776
- if ".tar.gz" in str(self) or ".tgz" in str(self):
689
+ if str(self).endswith(".tar.gz") or str(self).endswith(".tgz"):
777
690
  # res = self.ungz_untar(folder=folder, path=path, name=name, inplace=inplace, verbose=verbose, orig=orig)
778
691
  return self.ungz(name=f"tmp_{randstr()}.tar", inplace=inplace).untar(folder=folder, name=name, path=path, inplace=True, orig=orig, verbose=verbose) # this works for .tgz suffix as well as .tar.gz
779
- elif ".gz" in str(self):
692
+ elif str(self).endswith(".tar"):
693
+ res = self.untar(folder=folder, name=name, path=path, inplace=inplace, orig=orig, verbose=verbose)
694
+ elif str(self).endswith(".gz"):
780
695
  res = self.ungz(folder=folder, path=path, name=name, inplace=inplace, verbose=verbose, orig=orig)
781
- elif ".tar.bz" in str(self) or "tbz" in str(self):
696
+ elif str(self).endswith(".tar.bz") or str(self).endswith(".tbz"):
782
697
  res = self.unbz(name=f"tmp_{randstr()}.tar", inplace=inplace)
783
698
  return res.untar(folder=folder, name=name, path=path, inplace=True, orig=orig, verbose=verbose)
784
- elif ".tar.xz" in str(self):
699
+ elif str(self).endswith(".tar.xz"):
785
700
  # res = self.unxz_untar(folder=folder, path=path, name=name, inplace=inplace, verbose=verbose, orig=orig)
786
701
  res = self.unxz(inplace=inplace).untar(folder=folder, name=name, path=path, inplace=True, orig=orig, verbose=verbose)
787
- elif ".zip" in str(self):
702
+ elif str(self).endswith(".zip"):
788
703
  res = self.unzip(folder=folder, path=path, name=name, inplace=inplace, verbose=verbose, orig=orig)
704
+ elif str(self).endswith(".7z"):
705
+ def unzip_7z(archive_path: str, dest_dir: Optional[str] = None) -> Path:
706
+ """
707
+ Uncompresses a .7z archive to a directory and returns the Path to the extraction directory.
708
+
709
+ :param archive_path: path to the .7z archive file
710
+ :param dest_dir: optional path to directory to extract into; if None a temporary dir will be created
711
+ :return: pathlib.Path pointing to the destination directory where contents were extracted
712
+ :raises: FileNotFoundError if archive does not exist; py7zr.Bad7zFile or other error if extraction fails
713
+ """
714
+ import py7zr # type: ignore
715
+ import tempfile
716
+ from pathlib import Path
717
+ archive_path_obj = Path(archive_path)
718
+ if not archive_path_obj.is_file():
719
+ raise FileNotFoundError(f"Archive file not found: {archive_path_obj!r}")
720
+ if dest_dir is None:
721
+ # create a temporary directory
722
+ dest = Path(tempfile.mkdtemp(prefix=f"unzip7z_{archive_path_obj.stem}_"))
723
+ else:
724
+ dest = Path(dest_dir)
725
+ dest.mkdir(parents=True, exist_ok=True)
726
+ # Perform extraction
727
+ with py7zr.SevenZipFile(str(archive_path_obj), mode='r') as archive:
728
+ archive.extractall(path=str(dest))
729
+ # Return the extraction directory path
730
+ return dest
731
+ from machineconfig.utils.code import run_lambda_function
732
+ destination_dir = str(self.expanduser().resolve()).replace(".7z", "")
733
+ run_lambda_function(lambda: unzip_7z(archive_path=str(self), dest_dir=destination_dir), uv_project_dir=None, uv_with=["py7zr"])
734
+ res = PathExtended(destination_dir)
789
735
  else:
790
736
  res = self
791
737
  return res
@@ -863,7 +809,7 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
863
809
  path = self
864
810
  else:
865
811
  try:
866
- path = self.rel2home()
812
+ path = PathExtended(self.expanduser().absolute().relative_to(Path.home()))
867
813
  except ValueError as ve:
868
814
  if strict:
869
815
  raise ve
@@ -911,9 +857,10 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
911
857
  rp = localpath.get_remote_path(root=root, os_specific=os_specific, rel2home=rel2home, strict=strict) # if rel2home else (P(root) / localpath if root is not None else localpath)
912
858
  else:
913
859
  rp = PathExtended(remotepath)
914
-
915
860
  from rclone_python import rclone
861
+ print(f"⬆️ UPLOADING {repr(localpath)} TO {cloud}:{rp.as_posix()}`") if verbose else None
916
862
  rclone.copyto(in_path=localpath.as_posix(), out_path=f"{cloud}:{rp.as_posix()}", )
863
+
917
864
  _ = [item.delete(sure=True) for item in to_del]
918
865
  if verbose:
919
866
  print(f"{'⬆️' * 5} UPLOAD COMPLETED.")
@@ -924,7 +871,6 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
924
871
  command = f"rclone link '{cloud}:{rp.as_posix()}'"
925
872
  completed = _run_shell_command(command, shell_to_use)
926
873
  from machineconfig.utils.terminal import Response
927
-
928
874
  res = Response.from_completed_process(completed).capture()
929
875
  tmp = res.op2path(strict_err=False, strict_returncode=False)
930
876
  if tmp is None: