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,257 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from typing import Optional, Any, Callable
|
|
3
|
+
|
|
4
|
+
import polars as pl
|
|
5
|
+
|
|
6
|
+
from sqlalchemy.orm import sessionmaker
|
|
7
|
+
from sqlalchemy import create_engine, text, inspect as inspect__
|
|
8
|
+
from sqlalchemy.engine import Engine
|
|
9
|
+
from sqlalchemy.sql.schema import MetaData
|
|
10
|
+
from pathlib import Path as P
|
|
11
|
+
|
|
12
|
+
OPLike = Optional[P] | str | None
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DBMS:
|
|
16
|
+
def __init__(self, engine: Engine):
|
|
17
|
+
self.eng: Engine = engine
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def from_local_db(path: OPLike = None, echo: bool = False, share_across_threads: bool = False, pool_size: int = 5, **kwargs: Any):
|
|
21
|
+
return DBMS(engine=DBMS.make_sql_engine(path=path, echo=echo, share_across_threads=share_across_threads, pool_size=pool_size, **kwargs))
|
|
22
|
+
|
|
23
|
+
def __repr__(self): return f"DataBase @ {self.eng}"
|
|
24
|
+
def close(self, sleep: int = 2):
|
|
25
|
+
self.eng.pool.dispose()
|
|
26
|
+
self.eng.dispose()
|
|
27
|
+
time.sleep(sleep)
|
|
28
|
+
@staticmethod
|
|
29
|
+
def _get_table_identifier(engine: Engine, table: str, sch: Optional[str]):
|
|
30
|
+
if sch is not None:
|
|
31
|
+
# Handle DuckDB schema names that contain dots (e.g., "klines.main")
|
|
32
|
+
if engine.url.drivername == 'duckdb' and '.' in sch and sch.endswith('.main'):
|
|
33
|
+
# For DuckDB schemas like "klines.main", just use the table name without schema
|
|
34
|
+
return f'"{table}"'
|
|
35
|
+
else:
|
|
36
|
+
return f'"{sch}"."{table}"'
|
|
37
|
+
else:
|
|
38
|
+
return f'"{table}"'
|
|
39
|
+
|
|
40
|
+
# ==================== QUERIES =====================================
|
|
41
|
+
def execute_as_you_go(self, *commands: str, res_func: Callable[[Any], Any] = lambda x: x.all(), df: bool = False):
|
|
42
|
+
with self.eng.begin() as conn:
|
|
43
|
+
result = None
|
|
44
|
+
for command in commands:
|
|
45
|
+
result = conn.execute(text(command))
|
|
46
|
+
# conn.commit() # if driver is sqlite3, the connection is autocommitting. # this commit is only needed in case of DBAPI driver.
|
|
47
|
+
return res_func(result) if not df else pl.DataFrame(res_func(result))
|
|
48
|
+
|
|
49
|
+
def execute_begin_once(self, command: str, res_func: Callable[[Any], Any] = lambda x: x.all(), df: bool = False):
|
|
50
|
+
with self.eng.begin() as conn:
|
|
51
|
+
result = conn.execute(text(command)) # no need for commit regardless of driver
|
|
52
|
+
result = res_func(result)
|
|
53
|
+
return result if not df else pl.DataFrame(result)
|
|
54
|
+
|
|
55
|
+
def execute(self, command: str):
|
|
56
|
+
with self.eng.begin() as conn:
|
|
57
|
+
result = conn.execute(text(command))
|
|
58
|
+
# conn.commit()
|
|
59
|
+
return result
|
|
60
|
+
|
|
61
|
+
# def execute_script(self, command: str, df: bool = False):
|
|
62
|
+
# with self.eng.begin() as conn: result = conn.executescript(text(command))
|
|
63
|
+
# return result if not df else pl.DataFrame(result)
|
|
64
|
+
|
|
65
|
+
# ========================== TABLES =====================================
|
|
66
|
+
def insert_dicts(self, table: str, *mydicts: dict[str, Any]) -> None:
|
|
67
|
+
cmd = f"""INSERT INTO {table} VALUES """
|
|
68
|
+
for mydict in mydicts: cmd += f"""({tuple(mydict)}), """
|
|
69
|
+
self.execute_begin_once(cmd)
|
|
70
|
+
|
|
71
|
+
def refresh(self, sch: Optional[str] = None) -> dict[str, Any]:
|
|
72
|
+
con = self.eng.connect()
|
|
73
|
+
ses = sessionmaker()(bind=self.eng)
|
|
74
|
+
meta = MetaData()
|
|
75
|
+
meta.reflect(bind=self.eng, schema=sch)
|
|
76
|
+
insp = inspect__(subject=self.eng)
|
|
77
|
+
schema = insp.get_schema_names()
|
|
78
|
+
sch_tab = {k: v for k, v in zip(schema, [insp.get_table_names(schema=x) for x in schema])}
|
|
79
|
+
sch_vws = {k: v for k, v in zip(schema, [insp.get_view_names(schema=x) for x in schema])}
|
|
80
|
+
return {'con': con, 'ses': ses, 'meta': meta, 'insp': insp, 'schema': schema, 'sch_tab': sch_tab, 'sch_vws': sch_vws}
|
|
81
|
+
|
|
82
|
+
def get_columns(self, table: str, sch: Optional[str] = None) -> list[str]:
|
|
83
|
+
meta = MetaData()
|
|
84
|
+
meta.reflect(bind=self.eng, schema=sch)
|
|
85
|
+
return list(meta.tables[self._get_table_identifier(self.eng, table, sch)].exported_columns.keys())
|
|
86
|
+
|
|
87
|
+
def read_table(self, table: Optional[str] = None, sch: Optional[str] = None, size: int = 5) -> pl.DataFrame:
|
|
88
|
+
insp = inspect__(self.eng)
|
|
89
|
+
schema = insp.get_schema_names()
|
|
90
|
+
sch_tab = {k: v for k, v in zip(schema, [insp.get_table_names(schema=x) for x in schema])}
|
|
91
|
+
if sch is None:
|
|
92
|
+
# First try to find schemas that have tables (excluding system schemas)
|
|
93
|
+
schemas_with_tables = []
|
|
94
|
+
for schema_name in schema:
|
|
95
|
+
if schema_name not in ["information_schema", "pg_catalog", "system"]:
|
|
96
|
+
if schema_name in sch_tab and len(sch_tab[schema_name]) > 0:
|
|
97
|
+
schemas_with_tables.append(schema_name)
|
|
98
|
+
|
|
99
|
+
if len(schemas_with_tables) == 0:
|
|
100
|
+
raise ValueError(f"No schemas with tables found. Available schemas: {schema}")
|
|
101
|
+
|
|
102
|
+
# Prefer non-"main" schemas if available, otherwise use main
|
|
103
|
+
if len(schemas_with_tables) > 1 and "main" in schemas_with_tables:
|
|
104
|
+
sch = [s for s in schemas_with_tables if s != "main"][0]
|
|
105
|
+
else:
|
|
106
|
+
sch = schemas_with_tables[0]
|
|
107
|
+
print(f"Auto-selected schema: `{sch}` from available schemas: {schemas_with_tables}")
|
|
108
|
+
|
|
109
|
+
if table is None:
|
|
110
|
+
if sch not in sch_tab:
|
|
111
|
+
raise ValueError(f"Schema `{sch}` not found. Available schemas: {list(sch_tab.keys())}")
|
|
112
|
+
tables = sch_tab[sch]
|
|
113
|
+
assert len(tables) > 0, f"No tables found in schema `{sch}`"
|
|
114
|
+
import random
|
|
115
|
+
table = random.choice(tables)
|
|
116
|
+
print(f"Reading table `{table}` from schema `{sch}`")
|
|
117
|
+
with self.eng.connect() as conn:
|
|
118
|
+
try:
|
|
119
|
+
res = conn.execute(text(f'''SELECT * FROM {self._get_table_identifier(self.eng, table, sch)} '''))
|
|
120
|
+
return pl.DataFrame(res.fetchmany(size))
|
|
121
|
+
except Exception:
|
|
122
|
+
print(f"Error executing query for table `{table}` in schema `{sch}`")
|
|
123
|
+
print(f"Available schemas and tables: {sch_tab}")
|
|
124
|
+
raise
|
|
125
|
+
|
|
126
|
+
def describe_db(self, sch: Optional[str] = None) -> pl.DataFrame:
|
|
127
|
+
meta = MetaData()
|
|
128
|
+
meta.reflect(bind=self.eng, schema=sch)
|
|
129
|
+
ses = sessionmaker()(bind=self.eng)
|
|
130
|
+
res_all = []
|
|
131
|
+
from rich.progress import Progress
|
|
132
|
+
with Progress() as progress:
|
|
133
|
+
task = progress.add_task("Inspecting tables", total=len(meta.sorted_tables))
|
|
134
|
+
for tbl in meta.sorted_tables:
|
|
135
|
+
table = tbl.name
|
|
136
|
+
if sch is not None:
|
|
137
|
+
table = f"{sch}.{table}"
|
|
138
|
+
count = ses.query(tbl).count()
|
|
139
|
+
res = dict(table=table, count=count, size_mb=count * len(tbl.exported_columns) * 10 / 1e6,
|
|
140
|
+
columns=len(tbl.exported_columns), schema=sch)
|
|
141
|
+
res_all.append(res)
|
|
142
|
+
progress.update(task, advance=1)
|
|
143
|
+
return pl.DataFrame(res_all)
|
|
144
|
+
|
|
145
|
+
def describe_table(self, table: str, sch: Optional[str] = None, dtype: bool = True) -> None:
|
|
146
|
+
print(table.center(100, "="))
|
|
147
|
+
meta = MetaData()
|
|
148
|
+
meta.reflect(bind=self.eng, schema=sch)
|
|
149
|
+
tbl = meta.tables[self._get_table_identifier(self.eng, table, sch)]
|
|
150
|
+
ses = sessionmaker()(bind=self.eng)
|
|
151
|
+
count = ses.query(tbl).count()
|
|
152
|
+
res = dict(name=table, count=count, size_mb=count * len(tbl.exported_columns) * 10 / 1e6)
|
|
153
|
+
from machineconfig.utils.accessories import pprint
|
|
154
|
+
pprint(res, title="TABLE DETAILS")
|
|
155
|
+
dat = self.read_table(table=table, sch=sch, size=2)
|
|
156
|
+
df = dat
|
|
157
|
+
print("SAMPLE:\n", df)
|
|
158
|
+
insp = inspect__(self.eng)
|
|
159
|
+
if dtype: print("\nDETAILED COLUMNS:\n", pl.DataFrame(insp.get_columns(self._get_table_identifier(self.eng, table, sch))))
|
|
160
|
+
print("\n" * 3)
|
|
161
|
+
|
|
162
|
+
@staticmethod
|
|
163
|
+
def make_sql_engine(path: OPLike = None, echo: bool = False, share_across_threads: bool = False, pool_size: int = 5, **kwargs: Any) -> Engine:
|
|
164
|
+
if path is None:
|
|
165
|
+
url = 'sqlite:///:memory:'
|
|
166
|
+
elif isinstance(path, str) and path.startswith(('sqlite://', 'postgresql://', 'mysql://', 'duckdb://')):
|
|
167
|
+
url = path
|
|
168
|
+
else:
|
|
169
|
+
path_str = str(P(path))
|
|
170
|
+
if path_str.endswith('.duckdb'):
|
|
171
|
+
url = f'duckdb:///{path_str}'
|
|
172
|
+
else:
|
|
173
|
+
url = f'sqlite:///{path_str}'
|
|
174
|
+
connect_args = {}
|
|
175
|
+
if share_across_threads and 'sqlite' in url:
|
|
176
|
+
connect_args['check_same_thread'] = False
|
|
177
|
+
return create_engine(url, echo=echo, pool_size=pool_size, connect_args=connect_args, **kwargs)
|
|
178
|
+
|
|
179
|
+
DB_TMP_PATH = P.home().joinpath(".tmp").joinpath("tmp_dbs").joinpath("results").joinpath("data.sqlite")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def to_db(table: str, idx: int, idx_max: int, data: Any):
|
|
183
|
+
import pickle
|
|
184
|
+
DB_TMP_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
185
|
+
db = DBMS.from_local_db(DB_TMP_PATH)
|
|
186
|
+
time_now = time.time_ns()
|
|
187
|
+
data_blob = pickle.dumps(data)
|
|
188
|
+
create_table = f"""CREATE TABLE IF NOT EXISTS "{table}" (time INT PRIMARY KEY, idx INT, idx_max INT, data BLOB)"""
|
|
189
|
+
insert_row = f"""INSERT INTO "{table}" (time, idx, idx_max, data) VALUES (:time, :idx, :idx_max, :data)"""
|
|
190
|
+
with db.eng.begin() as conn:
|
|
191
|
+
conn.execute(text(create_table))
|
|
192
|
+
conn.execute(
|
|
193
|
+
text(insert_row),
|
|
194
|
+
{'time': time_now, 'idx': idx, 'idx_max': idx_max, 'data': data_blob}
|
|
195
|
+
)
|
|
196
|
+
db.close()
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def from_db(table: str):
|
|
200
|
+
import pickle
|
|
201
|
+
DB_TMP_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
202
|
+
db = DBMS.from_local_db(DB_TMP_PATH)
|
|
203
|
+
with db.eng.connect() as conn:
|
|
204
|
+
res = conn.execute(text(f"""SELECT * FROM "{table}" """))
|
|
205
|
+
records = res.fetchall()
|
|
206
|
+
df = pl.DataFrame(records, schema=['time', 'idx', 'idx_max', 'data'])
|
|
207
|
+
df = df.with_columns(pl.col('data').map_elements(pickle.loads))
|
|
208
|
+
return df
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def get_table_specs(engine: Engine, table_name: str) -> pl.DataFrame:
|
|
212
|
+
inspector = inspect__(engine)
|
|
213
|
+
# Collect table information
|
|
214
|
+
columns_info = [{
|
|
215
|
+
'name': col['name'],
|
|
216
|
+
'type': str(col['type']),
|
|
217
|
+
'nullable': col['nullable'],
|
|
218
|
+
'default': col['default'],
|
|
219
|
+
'autoincrement': col.get('autoincrement'),
|
|
220
|
+
'category': 'column'
|
|
221
|
+
} for col in inspector.get_columns(table_name)]
|
|
222
|
+
# Primary keys
|
|
223
|
+
pk_info = [{
|
|
224
|
+
'name': pk,
|
|
225
|
+
'type': None,
|
|
226
|
+
'nullable': False,
|
|
227
|
+
'default': None,
|
|
228
|
+
'autoincrement': None,
|
|
229
|
+
'category': 'primary_key'
|
|
230
|
+
} for pk in inspector.get_pk_constraint(table_name)['constrained_columns']]
|
|
231
|
+
# Foreign keys
|
|
232
|
+
fk_info = [{
|
|
233
|
+
'name': fk['constrained_columns'][0],
|
|
234
|
+
'type': f"FK -> {fk['referred_table']}.{fk['referred_columns'][0]}",
|
|
235
|
+
'nullable': None,
|
|
236
|
+
'default': None,
|
|
237
|
+
'autoincrement': None,
|
|
238
|
+
'category': 'foreign_key'
|
|
239
|
+
} for fk in inspector.get_foreign_keys(table_name)]
|
|
240
|
+
# Indexe
|
|
241
|
+
index_info = [{
|
|
242
|
+
'name': idx['name'],
|
|
243
|
+
'type': f"Index on {', '.join(col for col in idx['column_names'] if col)}",
|
|
244
|
+
'nullable': None,
|
|
245
|
+
'default': None,
|
|
246
|
+
'autoincrement': None,
|
|
247
|
+
'category': 'index',
|
|
248
|
+
'unique': idx['unique']
|
|
249
|
+
} for idx in inspector.get_indexes(table_name)]
|
|
250
|
+
# Combine all information
|
|
251
|
+
all_info = columns_info + pk_info + fk_info + index_info
|
|
252
|
+
# Convert to DataFrame
|
|
253
|
+
df = pl.DataFrame(all_info)
|
|
254
|
+
return df
|
|
255
|
+
|
|
256
|
+
if __name__ == '__main__':
|
|
257
|
+
pass
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
|
|
2
|
+
import glob
|
|
3
|
+
import os
|
|
4
|
+
import platform
|
|
5
|
+
import random
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from rich import pretty
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def print_header():
|
|
12
|
+
console = Console()
|
|
13
|
+
pretty.install()
|
|
14
|
+
|
|
15
|
+
# Environment Information Panel
|
|
16
|
+
from rich.panel import Panel
|
|
17
|
+
from rich.table import Table
|
|
18
|
+
|
|
19
|
+
table = Table(show_header=False, show_edge=False, pad_edge=False)
|
|
20
|
+
table.add_column("Label", style="cyan", no_wrap=True)
|
|
21
|
+
table.add_column("Value", style="white")
|
|
22
|
+
|
|
23
|
+
table.add_row("Python Version", platform.python_version())
|
|
24
|
+
table.add_row("Operating System", platform.system())
|
|
25
|
+
table.add_row("Virtual Environment", os.getenv('VIRTUAL_ENV', 'None'))
|
|
26
|
+
table.add_row("Running @", str(Path.cwd()))
|
|
27
|
+
|
|
28
|
+
from machineconfig.utils.installer_utils.installer_runner import get_machineconfig_version
|
|
29
|
+
|
|
30
|
+
console.print(Panel(table, title=f"[bold blue]✨ 🐊 Machineconfig Shell {get_machineconfig_version()} ✨ Made with 🐍 | Built with ❤️[/bold blue]", border_style="blue"))
|
|
31
|
+
def print_logo(logo: str):
|
|
32
|
+
from machineconfig.utils.files.ascii_art import font_box_color, character_color, character_or_box_color
|
|
33
|
+
if platform.system() == "Windows":
|
|
34
|
+
_1x = Path.home().joinpath(r"AppData/Roaming/npm/figlet").exists()
|
|
35
|
+
_2x = Path.home().joinpath(r"AppData/Roaming/npm/lolcatjs").exists()
|
|
36
|
+
_3x = Path.home().joinpath(r"AppData/Local/Microsoft/WindowsApps/boxes.exe").exists()
|
|
37
|
+
if _1x and _2x and _3x:
|
|
38
|
+
if random.choice([True, True, False]): font_box_color(logo)
|
|
39
|
+
else: character_color(logo)
|
|
40
|
+
else:
|
|
41
|
+
# print("\n" + "🚫 " + "-" * 70 + " 🚫")
|
|
42
|
+
# print("🔍 Missing ASCII art dependencies. Install with: iwr bit.ly/cfgasciiartwindows | iex")
|
|
43
|
+
# print("🚫 " + "-" * 70 + " 🚫\n")
|
|
44
|
+
_default_art = Path(random.choice(glob.glob(str(Path(__file__).parent.joinpath("art", "*")))))
|
|
45
|
+
print(_default_art.read_text())
|
|
46
|
+
elif platform.system() in ["Linux", "Darwin"]: # Explicitly handle both Linux and macOS
|
|
47
|
+
from machineconfig.utils.installer_utils.installer_locator_utils import is_executable_in_path
|
|
48
|
+
avail_cowsay = is_executable_in_path("cowsay")
|
|
49
|
+
avail_lolcat = is_executable_in_path("lolcat")
|
|
50
|
+
avail_boxes = is_executable_in_path("boxes")
|
|
51
|
+
avail_figlet = is_executable_in_path("figlet")
|
|
52
|
+
if avail_cowsay and avail_lolcat and avail_boxes and avail_figlet:
|
|
53
|
+
# _dynamic_art = random.choice([True, True, True, True, False])
|
|
54
|
+
# if _dynamic_art: character_or_box_color(logo=logo)
|
|
55
|
+
# else:
|
|
56
|
+
# print(Path(random.choice(glob.glob(str(Path(__file__).parent.joinpath("art", "*"))))).read_text())
|
|
57
|
+
character_or_box_color(logo=logo)
|
|
58
|
+
else:
|
|
59
|
+
print("\n" + "🚫 " + "-" * 70 + " 🚫")
|
|
60
|
+
install_cmd = "devops install --group TerminalEyeCandy" if platform.system() == "Linux" else "brew install cowsay lolcat boxes figlet"
|
|
61
|
+
print(f"🔍 Missing ASCII art dependencies. Install with: {install_cmd}")
|
|
62
|
+
print("🚫 " + "-" * 70 + " 🚫\n")
|
|
63
|
+
_default_art = Path(random.choice(glob.glob(str(Path(__file__).parent.joinpath("art", "*")))))
|
|
64
|
+
print(_default_art.read_text())
|
|
65
|
+
else:
|
|
66
|
+
print(f"⚠️ Platform {platform.system()} not supported for ASCII art. Using default art.")
|
|
67
|
+
_default_art = Path(random.choice(glob.glob(str(Path(__file__).parent.joinpath("art", "*")))))
|
|
68
|
+
print(_default_art.read_text())
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from zipfile import ZipFile, BadZipFile
|
|
5
|
+
from typing import Union
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def decompress_and_remove_zip(zip_path: Union[str, Path]) -> None:
|
|
9
|
+
"""
|
|
10
|
+
Decompress a ZIP file and remove it after extraction.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
zip_path (Union[str, Path]): Path to the ZIP file.
|
|
14
|
+
|
|
15
|
+
Raises:
|
|
16
|
+
FileNotFoundError: If the zip file does not exist.
|
|
17
|
+
BadZipFile: If the file is not a valid ZIP archive.
|
|
18
|
+
PermissionError: If the file cannot be deleted due to permission issues.
|
|
19
|
+
Exception: For other unexpected errors.
|
|
20
|
+
"""
|
|
21
|
+
zip_path = Path(zip_path)
|
|
22
|
+
|
|
23
|
+
if not zip_path.exists():
|
|
24
|
+
raise FileNotFoundError(f"The file '{zip_path}' does not exist.")
|
|
25
|
+
|
|
26
|
+
if not zip_path.is_file():
|
|
27
|
+
raise FileNotFoundError(f"The path '{zip_path}' is not a file.")
|
|
28
|
+
|
|
29
|
+
extract_dir = zip_path.parent
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
with ZipFile(zip_path, 'r') as zip_ref:
|
|
33
|
+
zip_ref.extractall(extract_dir)
|
|
34
|
+
except BadZipFile as e:
|
|
35
|
+
raise BadZipFile(f"The file '{zip_path}' is not a valid zip archive.") from e
|
|
36
|
+
except Exception as e:
|
|
37
|
+
raise Exception(f"Failed to extract '{zip_path}': {e}") from e
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
zip_path.unlink()
|
|
41
|
+
except PermissionError as e:
|
|
42
|
+
raise PermissionError(f"Permission denied when deleting '{zip_path}'.") from e
|
|
43
|
+
except Exception as e:
|
|
44
|
+
raise Exception(f"Failed to delete '{zip_path}': {e}") from e
|
|
45
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Read:
|
|
9
|
+
@staticmethod
|
|
10
|
+
def read(path: 'Path', **kwargs: Any) -> Any:
|
|
11
|
+
if Path(path).is_dir(): raise IsADirectoryError(f"Path is a directory, not a file: {path}")
|
|
12
|
+
suffix = Path(path).suffix[1:]
|
|
13
|
+
if suffix == "": raise ValueError(f"File type could not be inferred from suffix. Suffix is empty. Path: {path}")
|
|
14
|
+
if suffix in ("sqlite", "sqlite3", "db", "duckdb"):
|
|
15
|
+
from machineconfig.utils.files.dbms import DBMS
|
|
16
|
+
res = DBMS.from_local_db(path=path)
|
|
17
|
+
print(res.describe_db())
|
|
18
|
+
return res
|
|
19
|
+
try: return getattr(Read, suffix)(str(path), **kwargs)
|
|
20
|
+
except AttributeError as err:
|
|
21
|
+
if "type object 'Read' has no attribute" not in str(err): raise AttributeError(err) from err
|
|
22
|
+
if suffix in ('eps', 'jpg', 'jpeg', 'pdf', 'pgf', 'png', 'ps', 'raw', 'rgba', 'svg', 'svgz', 'tif', 'tiff'):
|
|
23
|
+
import matplotlib.pyplot as pyplot
|
|
24
|
+
return pyplot.imread(str(path), **kwargs) # from: plt.gcf().canvas.get_supported_filetypes().keys():
|
|
25
|
+
if suffix == "parquet":
|
|
26
|
+
import polars as pl
|
|
27
|
+
return pl.read_parquet(path, **kwargs)
|
|
28
|
+
elif suffix == "csv":
|
|
29
|
+
import polars as pl
|
|
30
|
+
return pl.read_csv(path, **kwargs)
|
|
31
|
+
try:
|
|
32
|
+
# guess = install_n_import('magic', 'python-magic').from_file(path)
|
|
33
|
+
guess = "IDKm"
|
|
34
|
+
raise AttributeError(f"Unknown file type. failed to recognize the suffix `{suffix}`. According to libmagic1, the file seems to be: {guess}") from err
|
|
35
|
+
except ImportError as err2:
|
|
36
|
+
print(f"💥 Unknown file type. failed to recognize the suffix `{suffix}` of file {path} ")
|
|
37
|
+
raise ImportError(err) from err2
|
|
38
|
+
@staticmethod
|
|
39
|
+
def json(path: 'Path', r: bool = False, **kwargs: Any) -> Any: # return could be list or dict etc
|
|
40
|
+
from machineconfig.utils.io import read_json
|
|
41
|
+
return read_json(path, r=r, **kwargs)
|
|
42
|
+
@staticmethod
|
|
43
|
+
def yaml(path: 'Path', r: bool = False) -> Any: # return could be list or dict etc
|
|
44
|
+
import yaml
|
|
45
|
+
with open(str(path), "r", encoding="utf-8") as file:
|
|
46
|
+
mydict = yaml.load(file, Loader=yaml.FullLoader)
|
|
47
|
+
_ = r
|
|
48
|
+
return mydict
|
|
49
|
+
@staticmethod
|
|
50
|
+
def ini(path: 'Path', encoding: Optional[str] = None):
|
|
51
|
+
if not Path(path).exists() or Path(path).is_dir(): raise FileNotFoundError(f"File not found or is a directory: {path}")
|
|
52
|
+
import configparser
|
|
53
|
+
res = configparser.ConfigParser()
|
|
54
|
+
res.read(filenames=[str(path)], encoding=encoding)
|
|
55
|
+
return res
|
|
56
|
+
@staticmethod
|
|
57
|
+
def toml(path: 'Path'):
|
|
58
|
+
import tomllib
|
|
59
|
+
return tomllib.loads(Path(path).read_text(encoding='utf-8'))
|
|
60
|
+
@staticmethod
|
|
61
|
+
def npy(path: 'Path', **kwargs: Any):
|
|
62
|
+
import numpy as np
|
|
63
|
+
data = np.load(str(path), allow_pickle=True, **kwargs)
|
|
64
|
+
# data = data.item() if data.dtype == np.object else data
|
|
65
|
+
return data
|
|
66
|
+
@staticmethod
|
|
67
|
+
def pickle(path: 'Path', **kwargs: Any):
|
|
68
|
+
import pickle
|
|
69
|
+
try: return pickle.loads(Path(path).read_bytes(), **kwargs)
|
|
70
|
+
except BaseException as ex:
|
|
71
|
+
print(f"💥 Failed to load pickle file `{path}` with error:\n{ex}")
|
|
72
|
+
raise ex
|
|
73
|
+
@staticmethod
|
|
74
|
+
def pkl(path: 'Path', **kwargs: Any): return Read.pickle(path, **kwargs)
|
|
75
|
+
# @staticmethod
|
|
76
|
+
# def dill(path: 'Path', **kwargs: Any) -> Any:
|
|
77
|
+
# """handles imports automatically provided that saved object was from an imported class (not in defined in __main__)"""
|
|
78
|
+
# import dill
|
|
79
|
+
# obj = dill.loads(str=Path(path).read_bytes(), **kwargs)
|
|
80
|
+
# return obj
|
|
81
|
+
@staticmethod
|
|
82
|
+
def py(path: 'Path', init_globals: Optional[dict[str, Any]] = None, run_name: Optional[str] = None):
|
|
83
|
+
import runpy
|
|
84
|
+
return runpy.run_path(str(path), init_globals=init_globals, run_name=run_name)
|
|
85
|
+
@staticmethod
|
|
86
|
+
def txt(path: 'Path', encoding: str = 'utf-8') -> str: return Path(path).read_text(encoding=encoding)
|
|
87
|
+
@staticmethod
|
|
88
|
+
def parquet(path: 'Path', **kwargs: Any):
|
|
89
|
+
import polars as pl
|
|
90
|
+
return pl.read_parquet(path, **kwargs)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if __name__ == '__main__':
|
|
95
|
+
pass
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Script to fetch GitHub release information from installer JSON files.
|
|
4
|
+
Extracts GitHub repository URLs and fetches latest release data with rate limiting.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import time
|
|
9
|
+
import subprocess
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any, Dict, Optional, Set
|
|
12
|
+
from urllib.parse import urlparse
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def is_github_repo(url: str) -> bool:
|
|
16
|
+
"""Check if URL is a GitHub repository URL."""
|
|
17
|
+
try:
|
|
18
|
+
parsed = urlparse(url)
|
|
19
|
+
return parsed.netloc == "github.com" and len(parsed.path.split("/")) >= 3
|
|
20
|
+
except Exception:
|
|
21
|
+
return False
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def extract_github_repos_from_json(json_file_path: Path) -> Set[str]:
|
|
25
|
+
"""Extract GitHub repository URLs from installer JSON file."""
|
|
26
|
+
github_repos: Set[str] = set()
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
with open(json_file_path, 'r', encoding='utf-8') as file:
|
|
30
|
+
data = json.load(file)
|
|
31
|
+
|
|
32
|
+
for installer in data.get("installers", []):
|
|
33
|
+
repo_url = installer.get("repoURL", "")
|
|
34
|
+
if is_github_repo(repo_url):
|
|
35
|
+
github_repos.add(repo_url)
|
|
36
|
+
|
|
37
|
+
except (json.JSONDecodeError, FileNotFoundError) as e:
|
|
38
|
+
print(f"Error reading {json_file_path}: {e}")
|
|
39
|
+
|
|
40
|
+
return github_repos
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get_repo_name_from_url(repo_url: str) -> str:
|
|
44
|
+
"""Extract owner/repo from GitHub URL."""
|
|
45
|
+
try:
|
|
46
|
+
parsed = urlparse(repo_url)
|
|
47
|
+
path_parts = parsed.path.strip("/").split("/")
|
|
48
|
+
return f"{path_parts[0]}/{path_parts[1]}"
|
|
49
|
+
except (IndexError, AttributeError):
|
|
50
|
+
return ""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def fetch_github_release_data(repo_name: str) -> Optional[Dict[str, Any]]:
|
|
54
|
+
"""Fetch latest release data from GitHub API using curl."""
|
|
55
|
+
try:
|
|
56
|
+
cmd = [
|
|
57
|
+
"curl", "-s",
|
|
58
|
+
f"https://api.github.com/repos/{repo_name}/releases/latest"
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
result = subprocess.run(
|
|
62
|
+
cmd,
|
|
63
|
+
capture_output=True,
|
|
64
|
+
text=True,
|
|
65
|
+
timeout=30
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
if result.returncode != 0:
|
|
69
|
+
print(f"❌ Failed to fetch data for {repo_name}: {result.stderr}")
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
response_data = json.loads(result.stdout)
|
|
73
|
+
|
|
74
|
+
# Check if API returned an error
|
|
75
|
+
if "message" in response_data:
|
|
76
|
+
if "API rate limit exceeded" in response_data.get("message", ""):
|
|
77
|
+
print(f"🚫 Rate limit exceeded for {repo_name}")
|
|
78
|
+
return None
|
|
79
|
+
elif "Not Found" in response_data.get("message", ""):
|
|
80
|
+
print(f"🔍 No releases found for {repo_name}")
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
return response_data
|
|
84
|
+
|
|
85
|
+
except (subprocess.TimeoutExpired, json.JSONDecodeError, subprocess.SubprocessError) as e:
|
|
86
|
+
print(f"❌ Error fetching {repo_name}: {e}")
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def extract_release_info(release_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
91
|
+
"""Extract relevant information from GitHub release data."""
|
|
92
|
+
if not release_data:
|
|
93
|
+
return {}
|
|
94
|
+
|
|
95
|
+
asset_names = [asset["name"] for asset in release_data.get("assets", [])]
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
"tag_name": release_data.get("tag_name", ""),
|
|
99
|
+
"name": release_data.get("name", ""),
|
|
100
|
+
"published_at": release_data.get("published_at", ""),
|
|
101
|
+
"assets": asset_names,
|
|
102
|
+
"assets_count": len(asset_names)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def main() -> None:
|
|
107
|
+
"""Main function to process installer JSON files and fetch GitHub release data."""
|
|
108
|
+
# Define paths
|
|
109
|
+
current_dir = Path(__file__).parent
|
|
110
|
+
installer_dir = current_dir.parent.parent / "jobs" / "installer"
|
|
111
|
+
|
|
112
|
+
standard_json = installer_dir / "installer_data.json"
|
|
113
|
+
output_json = current_dir / "github_releases.json"
|
|
114
|
+
|
|
115
|
+
print("🔍 Starting GitHub release data extraction...")
|
|
116
|
+
print(f"📁 Processing files from: {installer_dir}")
|
|
117
|
+
|
|
118
|
+
# Extract GitHub repositories from both files
|
|
119
|
+
all_github_repos: Set[str] = set()
|
|
120
|
+
|
|
121
|
+
if standard_json.exists():
|
|
122
|
+
print(f"📄 Reading {standard_json.name}...")
|
|
123
|
+
repos = extract_github_repos_from_json(standard_json)
|
|
124
|
+
all_github_repos.update(repos)
|
|
125
|
+
print(f" Found {len(repos)} GitHub repos")
|
|
126
|
+
else:
|
|
127
|
+
print(f"⚠️ File not found: {standard_json}")
|
|
128
|
+
print(f"🎯 Total unique GitHub repositories found: {len(all_github_repos)}")
|
|
129
|
+
|
|
130
|
+
if not all_github_repos:
|
|
131
|
+
print("❌ No GitHub repositories found. Exiting.")
|
|
132
|
+
return
|
|
133
|
+
|
|
134
|
+
# Fetch release data with rate limiting
|
|
135
|
+
release_mapping: Dict[str, Any] = {}
|
|
136
|
+
total_repos = len(all_github_repos)
|
|
137
|
+
|
|
138
|
+
print(f"\n🚀 Fetching release data for {total_repos} repositories...")
|
|
139
|
+
print("⏰ Rate limiting: 5 seconds between requests")
|
|
140
|
+
print("-" * 60)
|
|
141
|
+
|
|
142
|
+
for i, repo_url in enumerate(sorted(all_github_repos), 1):
|
|
143
|
+
repo_name = get_repo_name_from_url(repo_url)
|
|
144
|
+
|
|
145
|
+
if not repo_name:
|
|
146
|
+
print(f"⚠️ [{i:3d}/{total_repos}] Invalid repo URL: {repo_url}")
|
|
147
|
+
continue
|
|
148
|
+
|
|
149
|
+
print(f"📡 [{i:3d}/{total_repos}] Fetching: {repo_name}", end=" ... ")
|
|
150
|
+
|
|
151
|
+
release_data = fetch_github_release_data(repo_name)
|
|
152
|
+
|
|
153
|
+
if release_data:
|
|
154
|
+
release_info = extract_release_info(release_data)
|
|
155
|
+
release_mapping[repo_url] = release_info
|
|
156
|
+
assets_count = release_info.get("assets_count", 0)
|
|
157
|
+
tag = release_info.get("tag_name", "unknown")
|
|
158
|
+
print(f"✅ {tag} ({assets_count} assets)")
|
|
159
|
+
else:
|
|
160
|
+
release_mapping[repo_url] = {}
|
|
161
|
+
print("❌ No data")
|
|
162
|
+
|
|
163
|
+
# Rate limiting - wait 5 seconds between requests (except for the last one)
|
|
164
|
+
if i < total_repos:
|
|
165
|
+
time.sleep(5)
|
|
166
|
+
|
|
167
|
+
# Save results
|
|
168
|
+
output_data = {
|
|
169
|
+
"generated_at": time.strftime("%Y-%m-%d %H:%M:%S UTC", time.gmtime()),
|
|
170
|
+
"total_repositories": len(all_github_repos),
|
|
171
|
+
"successful_fetches": len([v for v in release_mapping.values() if v]),
|
|
172
|
+
"releases": release_mapping
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
with open(output_json, 'w', encoding='utf-8') as f:
|
|
176
|
+
json.dump(output_data, f, indent=2, ensure_ascii=False)
|
|
177
|
+
|
|
178
|
+
successful = len([v for v in release_mapping.values() if v])
|
|
179
|
+
print("\n📊 Summary:")
|
|
180
|
+
print(f" Total repositories processed: {len(all_github_repos)}")
|
|
181
|
+
print(f" Successful fetches: {successful}")
|
|
182
|
+
print(f" Failed fetches: {len(all_github_repos) - successful}")
|
|
183
|
+
print(f" Output saved to: {output_json}")
|
|
184
|
+
print("✅ Done!")
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
if __name__ == "__main__":
|
|
188
|
+
main()
|