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