machineconfig 6.82__py3-none-any.whl → 8.51__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.
- machineconfig/cluster/remote/cloud_manager.py +1 -1
- machineconfig/cluster/remote/run_cluster.py +1 -1
- machineconfig/cluster/remote/run_remote.py +1 -1
- machineconfig/cluster/sessions_managers/utils/maker.py +29 -15
- machineconfig/cluster/sessions_managers/wt_local.py +17 -222
- machineconfig/cluster/sessions_managers/wt_local_manager.py +56 -194
- machineconfig/cluster/sessions_managers/wt_remote_manager.py +42 -198
- 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_reporting.py +76 -0
- machineconfig/cluster/sessions_managers/wt_utils/wt_helpers.py +199 -0
- machineconfig/cluster/sessions_managers/zellij_local.py +1 -1
- machineconfig/cluster/sessions_managers/zellij_local_manager.py +4 -2
- machineconfig/cluster/sessions_managers/zellij_remote_manager.py +3 -2
- machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +2 -2
- machineconfig/jobs/installer/checks/check_installations.py +133 -0
- machineconfig/jobs/installer/checks/install_utils.py +132 -0
- machineconfig/jobs/installer/checks/report_utils.py +39 -0
- machineconfig/jobs/installer/checks/vt_utils.py +89 -0
- machineconfig/jobs/installer/installer_data.json +1500 -310
- machineconfig/jobs/installer/linux_scripts/docker.sh +6 -9
- machineconfig/jobs/installer/linux_scripts/q.sh +10 -7
- machineconfig/jobs/installer/linux_scripts/redis.sh +1 -0
- machineconfig/jobs/installer/package_groups.py +62 -91
- machineconfig/jobs/installer/powershell_scripts/install_fonts.ps1 +129 -34
- machineconfig/jobs/installer/{custom → python_scripts}/boxes.py +2 -3
- machineconfig/jobs/installer/{custom_dev → python_scripts}/brave.py +5 -3
- machineconfig/jobs/installer/python_scripts/cloudflare_warp_cli.py +23 -0
- machineconfig/jobs/installer/{custom_dev → python_scripts}/code.py +14 -9
- machineconfig/jobs/installer/{custom_dev → python_scripts}/dubdb_adbc.py +1 -1
- machineconfig/jobs/installer/python_scripts/hx.py +214 -0
- machineconfig/jobs/installer/{custom_dev → python_scripts}/nerdfont.py +2 -2
- machineconfig/jobs/installer/{custom_dev → python_scripts}/nerfont_windows_helper.py +32 -26
- machineconfig/jobs/installer/python_scripts/sysabc.py +145 -0
- machineconfig/jobs/installer/{custom_dev → python_scripts}/wezterm.py +2 -19
- machineconfig/jobs/installer/{custom_dev → python_scripts}/winget.py +10 -14
- machineconfig/jobs/installer/python_scripts/yazi.py +139 -0
- machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_nfs +0 -1
- machineconfig/jobs/scripts/powershell_scripts/cmatrix.ps1 +52 -0
- machineconfig/jobs/scripts/powershell_scripts/mount_ssh.ps1 +13 -0
- machineconfig/jobs/scripts/powershell_scripts/obs.ps1 +4 -0
- machineconfig/jobs/scripts_dynamic/a.py +428 -0
- machineconfig/logger.py +1 -2
- machineconfig/profile/create_helper.py +56 -18
- machineconfig/profile/create_links.py +79 -21
- machineconfig/profile/create_links_export.py +87 -36
- machineconfig/profile/create_shell_profile.py +92 -127
- machineconfig/profile/mapper_data.toml +45 -0
- machineconfig/profile/mapper_dotfiles.toml +249 -0
- machineconfig/scripts/__init__.py +0 -4
- machineconfig/scripts/linux/wrap_mcfg +46 -0
- machineconfig/scripts/nu/wrap_mcfg.nu +69 -0
- machineconfig/scripts/python/agents.py +85 -165
- machineconfig/scripts/python/ai/initai.py +4 -2
- machineconfig/scripts/python/ai/scripts/__init__.py +1 -0
- machineconfig/scripts/python/ai/scripts/command_runner.ps1 +33 -0
- machineconfig/scripts/python/ai/{command_runner → scripts}/command_runner.sh +1 -1
- machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +2 -0
- machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +8 -6
- machineconfig/scripts/python/ai/solutions/claude/claude.py +1 -1
- machineconfig/scripts/python/ai/solutions/cline/cline.py +1 -1
- machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Thinking-Beast-Mode.chatmode.md → agents/Thinking-Beast-Mode.agent.md} +0 -1
- machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md → agents/Ultimate-Transparent-Thinking-Beast-Mode.agent.md} +0 -1
- machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/deepResearch.chatmode.md → agents/deepResearch.agent.md} +2 -2
- machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +6 -6
- machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +33 -0
- machineconfig/scripts/python/ai/solutions/copilot/instructions/python/watch_exec.prompt.md +20 -0
- machineconfig/scripts/python/ai/solutions/crush/crush.py +1 -1
- machineconfig/scripts/python/ai/solutions/cursor/cursors.py +1 -1
- machineconfig/scripts/python/ai/solutions/gemini/gemini.py +1 -1
- machineconfig/scripts/python/ai/solutions/gemini/settings.json +3 -0
- machineconfig/scripts/python/ai/{generate_files.py → utils/generate_files.py} +2 -2
- machineconfig/scripts/python/ai/{solutions → utils}/generic.py +2 -15
- machineconfig/scripts/python/ai/{vscode_tasks.py → utils/vscode_tasks.py} +13 -5
- machineconfig/scripts/python/cloud.py +58 -11
- machineconfig/scripts/python/croshell.py +10 -162
- machineconfig/scripts/python/devops.py +73 -36
- machineconfig/scripts/python/devops_navigator.py +16 -6
- machineconfig/scripts/python/fire_jobs.py +8 -222
- machineconfig/scripts/python/ftpx.py +7 -200
- machineconfig/scripts/python/graph/cli_graph.json +8743 -0
- machineconfig/scripts/python/{env_manager → helper_env}/path_manager_tui.py +2 -2
- machineconfig/scripts/python/helpers/helper_env/env_manager_tui.py +204 -0
- machineconfig/scripts/python/helpers/helper_env/path_manager_tui.py +228 -0
- machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/agentic_frameworks/fire_crush.json +1 -1
- machineconfig/scripts/python/helpers/helpers_agents/agentic_frameworks/fire_crush.py +39 -0
- machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/agentic_frameworks/fire_cursor_agents.py +3 -4
- machineconfig/scripts/python/helpers/helpers_agents/agentic_frameworks/fire_gemini.py +55 -0
- machineconfig/scripts/python/helpers/helpers_agents/agentic_frameworks/fire_qwen.py +30 -0
- machineconfig/scripts/python/helpers/helpers_agents/agents_impl.py +168 -0
- machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/fire_agents_help_launch.py +38 -16
- machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/fire_agents_helper_types.py +11 -14
- machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/aichat/config.yaml +5 -0
- machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/aider/.aider.conf.yml +2 -0
- machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/copilot/config.yml +1 -0
- machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/crush/crush.json +10 -0
- machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/gemini/settings.json +12 -0
- machineconfig/scripts/python/helpers/helpers_agents/privacy/privacy.py +109 -0
- machineconfig/scripts/python/helpers/helpers_agents/templates/prompt.txt +10 -0
- machineconfig/scripts/python/helpers/helpers_agents/templates/template.sh +34 -0
- machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_copy.py +32 -25
- machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_mount.py +29 -22
- machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_sync.py +9 -8
- machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers2.py +1 -1
- machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/crosh.py +3 -3
- machineconfig/scripts/python/helpers/helpers_croshell/croshell_impl.py +225 -0
- machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/scheduler.py +4 -4
- machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/start_slidev.py +12 -12
- machineconfig/scripts/python/helpers/helpers_devops/backup_config.py +149 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_backup_retrieve.py +262 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_config.py +98 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_config_dotfile.py +274 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_data.py +67 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_nw.py +201 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_repos.py +274 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_self.py +197 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_share_file.py +151 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_share_server.py +125 -0
- machineconfig/scripts/python/{helpers_devops/cli_terminal.py → helpers/helpers_devops/cli_share_terminal.py} +26 -22
- machineconfig/scripts/python/helpers/helpers_devops/cli_ssh.py +167 -0
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_status.py +17 -23
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_update_repos.py +1 -1
- machineconfig/scripts/python/{interactive.py → helpers/helpers_devops/interactive.py} +78 -71
- machineconfig/scripts/python/helpers/helpers_devops/run_script.py +197 -0
- machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.ps1 +41 -0
- machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.sh +48 -0
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_wezterm_theme.py +4 -4
- machineconfig/scripts/python/{helpers_fire/helpers4.py → helpers/helpers_fire_command/file_wrangler.py} +57 -20
- machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_args_helper.py +1 -0
- machineconfig/scripts/python/helpers/helpers_fire_command/fire_jobs_impl.py +233 -0
- machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_route_helper.py +26 -16
- machineconfig/scripts/python/helpers/helpers_msearch/__init__.py +5 -0
- machineconfig/scripts/python/helpers/helpers_msearch/msearch_impl.py +248 -0
- machineconfig/scripts/{linux → python/helpers/helpers_msearch/scripts_linux}/fzfg +6 -5
- machineconfig/scripts/python/helpers/helpers_msearch/scripts_linux/search_with_context.sh +48 -0
- machineconfig/scripts/python/helpers/helpers_msearch/scripts_windows/fzfg.ps1 +59 -0
- machineconfig/scripts/python/helpers/helpers_navigator/__init__.py +20 -0
- machineconfig/scripts/python/helpers/helpers_navigator/cli_graph_loader.py +234 -0
- machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/command_builder.py +61 -13
- machineconfig/scripts/python/helpers/helpers_navigator/command_detail.py +153 -0
- machineconfig/scripts/python/helpers/helpers_navigator/command_tree.py +45 -0
- machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/data_models.py +18 -11
- machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/main_app.py +5 -5
- machineconfig/scripts/python/helpers/helpers_network/address.py +174 -0
- machineconfig/scripts/python/helpers/helpers_network/address_switch.py +78 -0
- machineconfig/scripts/python/helpers/helpers_network/ftpx_impl.py +276 -0
- machineconfig/scripts/python/{nw → helpers/helpers_network}/mount_nfs.py +2 -2
- machineconfig/scripts/python/{nw → helpers/helpers_network}/mount_ssh.py +3 -3
- machineconfig/scripts/python/helpers/helpers_network/ssh_add_identity.py +73 -0
- machineconfig/scripts/python/helpers/helpers_network/ssh_add_ssh_key.py +175 -0
- machineconfig/scripts/python/helpers/helpers_network/ssh_debug_linux.py +319 -0
- machineconfig/scripts/python/helpers/helpers_network/ssh_debug_windows.py +275 -0
- machineconfig/scripts/python/{nw → helpers/helpers_network}/wifi_conn.py +1 -53
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action.py +3 -3
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action_helper.py +3 -3
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/clone.py +0 -1
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/cloud_repo_sync.py +159 -48
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/grource.py +4 -3
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/record.py +33 -12
- machineconfig/scripts/python/helpers/helpers_repos/repo_analyzer_1.py +160 -0
- machineconfig/scripts/python/{helpers_repos/count_lines.py → helpers/helpers_repos/repo_analyzer_2.py} +156 -191
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/update.py +0 -6
- machineconfig/scripts/python/helpers/helpers_search/ast_search.py +74 -0
- machineconfig/scripts/python/helpers/helpers_search/qr_code.py +166 -0
- machineconfig/scripts/python/helpers/helpers_search/repo_rag.py +325 -0
- machineconfig/scripts/python/helpers/helpers_search/script_help.py +81 -0
- machineconfig/scripts/python/helpers/helpers_search/symantic_search.py +25 -0
- machineconfig/scripts/python/helpers/helpers_sessions/__init__.py +0 -0
- machineconfig/scripts/python/helpers/helpers_sessions/sessions_impl.py +186 -0
- machineconfig/scripts/python/{helpers_sessions → helpers/helpers_sessions}/sessions_multiprocess.py +20 -14
- machineconfig/scripts/python/helpers/helpers_terminal/__init__.py +0 -0
- machineconfig/scripts/python/helpers/helpers_terminal/terminal_impl.py +96 -0
- machineconfig/scripts/python/helpers/helpers_utils/download.py +150 -0
- machineconfig/scripts/python/helpers/helpers_utils/pdf.py +96 -0
- machineconfig/scripts/python/helpers/helpers_utils/python.py +210 -0
- machineconfig/scripts/python/helpers/helpers_utils/specs.py +246 -0
- machineconfig/scripts/python/mcfg_entry.py +143 -0
- machineconfig/scripts/python/msearch.py +26 -0
- machineconfig/scripts/python/sessions.py +69 -135
- machineconfig/scripts/python/terminal.py +58 -0
- machineconfig/scripts/python/utils.py +115 -38
- machineconfig/scripts/windows/wrap_mcfg.ps1 +63 -0
- machineconfig/settings/atuin/config.toml +294 -0
- machineconfig/settings/atuin/themes/catppuccin-mocha-mauve.toml +12 -0
- 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 +3 -2
- machineconfig/settings/lf/windows/lfcd.ps1 +1 -1
- machineconfig/settings/lf/windows/lfrc +14 -16
- machineconfig/settings/linters/.ruff.toml +2 -1
- machineconfig/settings/marimo/marimo.toml +1 -1
- machineconfig/settings/marimo/snippets/globalize.py +34 -0
- machineconfig/settings/mprocs/windows/mprocs.yaml +2 -2
- machineconfig/settings/shells/bash/init.sh +47 -12
- machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +1 -1
- machineconfig/settings/shells/nushell/config.nu +25 -33
- machineconfig/settings/shells/nushell/env.nu +21 -8
- machineconfig/settings/shells/nushell/init.nu +138 -0
- machineconfig/settings/shells/pwsh/init.ps1 +111 -17
- machineconfig/settings/shells/pwsh/search_pwsh_history.ps1 +99 -0
- machineconfig/settings/shells/starship/starship.toml +16 -0
- machineconfig/settings/shells/wezterm/wezterm.lua +6 -1
- machineconfig/settings/shells/wt/settings.json +27 -18
- machineconfig/settings/shells/zsh/init.sh +42 -23
- machineconfig/settings/television/cable_unix/alias.toml +8 -0
- machineconfig/settings/television/cable_unix/aws-buckets.toml +14 -0
- machineconfig/settings/television/cable_unix/aws-instances.toml +13 -0
- machineconfig/settings/television/cable_unix/bash-history.toml +8 -0
- machineconfig/settings/television/cable_unix/channels.toml +19 -0
- machineconfig/settings/television/cable_unix/dirs.toml +13 -0
- machineconfig/settings/television/cable_unix/distrobox-list.toml +42 -0
- machineconfig/settings/television/cable_unix/docker-images.toml +13 -0
- machineconfig/settings/television/cable_unix/dotfiles.toml +11 -0
- machineconfig/settings/television/cable_unix/env.toml +17 -0
- machineconfig/settings/television/cable_unix/files.toml +11 -0
- machineconfig/settings/television/cable_unix/fish-history.toml +8 -0
- machineconfig/settings/television/cable_unix/git-branch.toml +11 -0
- machineconfig/settings/television/cable_unix/git-diff.toml +10 -0
- machineconfig/settings/television/cable_unix/git-log.toml +12 -0
- machineconfig/settings/television/cable_unix/git-reflog.toml +12 -0
- machineconfig/settings/television/cable_unix/git-repos.toml +16 -0
- machineconfig/settings/television/cable_unix/guix.toml +20 -0
- machineconfig/settings/television/cable_unix/just-recipes.toml +18 -0
- machineconfig/settings/television/cable_unix/k8s-deployments.toml +36 -0
- machineconfig/settings/television/cable_unix/k8s-pods.toml +50 -0
- machineconfig/settings/television/cable_unix/k8s-services.toml +36 -0
- machineconfig/settings/television/cable_unix/man-pages.toml +24 -0
- machineconfig/settings/television/cable_unix/nu-history.toml +7 -0
- machineconfig/settings/television/cable_unix/procs.toml +20 -0
- machineconfig/settings/television/cable_unix/text.toml +17 -0
- machineconfig/settings/television/cable_unix/tldr.toml +18 -0
- machineconfig/settings/television/cable_unix/zsh-history.toml +9 -0
- machineconfig/settings/television/cable_windows/alias.toml +7 -0
- machineconfig/settings/television/cable_windows/dirs.toml +13 -0
- machineconfig/settings/television/cable_windows/docker-images.toml +13 -0
- machineconfig/settings/television/cable_windows/dotfiles.toml +11 -0
- machineconfig/settings/television/cable_windows/env.toml +17 -0
- machineconfig/settings/television/cable_windows/files.toml +14 -0
- machineconfig/settings/television/cable_windows/git-branch.toml +11 -0
- machineconfig/settings/television/cable_windows/git-diff.toml +10 -0
- machineconfig/settings/television/cable_windows/git-log.toml +11 -0
- machineconfig/settings/television/cable_windows/git-reflog.toml +11 -0
- machineconfig/settings/television/cable_windows/git-repos.toml +15 -0
- machineconfig/settings/television/cable_windows/nu-history.toml +7 -0
- machineconfig/settings/television/cable_windows/pwsh-history.toml +6 -0
- machineconfig/settings/television/cable_windows/text.toml +17 -0
- machineconfig/settings/tv/config.toml +234 -0
- machineconfig/settings/tv/themes/catppuccin-mocha-sky.toml +22 -0
- machineconfig/settings/wsl/.wslconfig +5 -30
- machineconfig/settings/wt/__init__.py +0 -0
- machineconfig/settings/yazi/init.lua +61 -0
- machineconfig/settings/yazi/keymap_linux.toml +94 -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/theme.toml +4 -0
- machineconfig/settings/yazi/yazi_linux.toml +94 -0
- machineconfig/settings/yazi/yazi_windows.toml +58 -0
- machineconfig/settings/zellij/layouts/st.kdl +40 -9
- machineconfig/settings/zellij/layouts/st2.kdl +1 -1
- machineconfig/setup_linux/__init__.py +2 -2
- machineconfig/setup_linux/apps_desktop.sh +8 -27
- machineconfig/setup_linux/web_shortcuts/interactive.sh +27 -12
- machineconfig/setup_linux/web_shortcuts/live_from_github.sh +34 -0
- machineconfig/setup_mac/__init__.py +1 -4
- machineconfig/setup_mac/apps_gui.sh +248 -0
- machineconfig/setup_windows/__init__.py +2 -5
- machineconfig/setup_windows/uv.ps1 +8 -1
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +28 -12
- machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +31 -0
- machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +17 -0
- machineconfig/type_hinting/sql/__init__.py +1 -0
- machineconfig/type_hinting/sql/base.py +216 -0
- machineconfig/type_hinting/sql/core_schema.py +64 -0
- machineconfig/type_hinting/sql/core_schema_typeddict.py +41 -0
- machineconfig/type_hinting/sql/typeddict_codegen.py +222 -0
- machineconfig/type_hinting/typedict/__init__.py +1 -0
- machineconfig/type_hinting/typedict/ast_utils.py +130 -0
- machineconfig/type_hinting/typedict/generator_helpers.py +319 -0
- machineconfig/type_hinting/typedict/generators.py +231 -0
- machineconfig/type_hinting/typedict/polars_schema.py +24 -0
- machineconfig/type_hinting/typedict/polars_schema_typeddict.py +63 -0
- machineconfig/utils/accessories.py +31 -4
- machineconfig/utils/code.py +163 -51
- machineconfig/utils/files/ascii_art.py +11 -15
- machineconfig/utils/files/headers.py +6 -7
- machineconfig/utils/files/read.py +8 -1
- machineconfig/utils/installer_utils/github_release_bulk.py +95 -138
- machineconfig/utils/installer_utils/github_release_scraper.py +99 -0
- machineconfig/utils/installer_utils/install_from_url.py +183 -0
- machineconfig/utils/installer_utils/installer_class.py +53 -102
- machineconfig/utils/installer_utils/installer_cli.py +161 -0
- machineconfig/utils/installer_utils/installer_helper.py +129 -0
- machineconfig/utils/installer_utils/{installer_abc.py → installer_locator_utils.py} +42 -91
- machineconfig/utils/{installer.py → installer_utils/installer_runner.py} +20 -65
- machineconfig/utils/io.py +94 -9
- machineconfig/utils/links.py +56 -38
- machineconfig/utils/meta.py +38 -21
- machineconfig/utils/options.py +81 -23
- machineconfig/utils/options_utils/__init__.py +0 -0
- machineconfig/utils/options_utils/options_tv_linux.py +211 -0
- machineconfig/utils/options_utils/options_tv_windows.py +88 -0
- machineconfig/utils/options_utils/tv_options.py +37 -0
- machineconfig/utils/path_extended.py +52 -102
- machineconfig/utils/path_helper.py +76 -23
- machineconfig/utils/procs.py +1 -1
- machineconfig/utils/scheduler.py +26 -53
- machineconfig/utils/scheduling.py +0 -2
- machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
- machineconfig/utils/schemas/layouts/layout_types.py +1 -1
- machineconfig/utils/source_of_truth.py +6 -1
- machineconfig/utils/ssh.py +216 -419
- machineconfig/utils/ssh_utils/abc.py +5 -0
- machineconfig/utils/ssh_utils/copy_from_here.py +116 -0
- machineconfig/utils/ssh_utils/copy_to_here.py +303 -0
- machineconfig/utils/ssh_utils/utils.py +158 -0
- machineconfig/utils/ssh_utils/wsl.py +147 -0
- machineconfig/utils/ssh_utils/wsl_helper.py +217 -0
- machineconfig/utils/terminal.py +1 -0
- machineconfig/utils/upgrade_packages.py +107 -35
- machineconfig/utils/ve.py +12 -4
- machineconfig-8.51.dist-info/METADATA +140 -0
- machineconfig-8.51.dist-info/RECORD +543 -0
- {machineconfig-6.82.dist-info → machineconfig-8.51.dist-info}/entry_points.txt +4 -1
- machineconfig/jobs/installer/check_installations.py +0 -248
- machineconfig/jobs/installer/custom/hx.py +0 -140
- machineconfig/jobs/installer/linux_scripts/pgsql.sh +0 -41
- machineconfig/jobs/installer/linux_scripts/timescaledb.sh +0 -71
- machineconfig/jobs/installer/powershell_scripts/archive_pygraphviz.ps1 +0 -12
- machineconfig/jobs/installer/powershell_scripts/openssh-server_add_key.ps1 +0 -7
- machineconfig/jobs/installer/powershell_scripts/openssh-server_copy-ssh-id.ps1 +0 -14
- machineconfig/profile/backup.toml +0 -49
- machineconfig/profile/mapper.toml +0 -256
- machineconfig/scripts/linux/fzf2g +0 -21
- machineconfig/scripts/linux/fzfag +0 -17
- machineconfig/scripts/linux/fzffg +0 -25
- machineconfig/scripts/linux/fzfrga +0 -21
- machineconfig/scripts/linux/mcfgs +0 -38
- machineconfig/scripts/linux/other/share_smb +0 -1
- machineconfig/scripts/linux/other/switch_ip +0 -20
- machineconfig/scripts/linux/skrg +0 -4
- machineconfig/scripts/linux/warp-cli.sh +0 -122
- machineconfig/scripts/linux/z_ls +0 -104
- machineconfig/scripts/python/ai/command_runner/prompt.txt +0 -9
- machineconfig/scripts/python/helpers_devops/cli_config.py +0 -120
- machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +0 -77
- machineconfig/scripts/python/helpers_devops/cli_data.py +0 -25
- machineconfig/scripts/python/helpers_devops/cli_nw.py +0 -73
- machineconfig/scripts/python/helpers_devops/cli_repos.py +0 -181
- machineconfig/scripts/python/helpers_devops/cli_self.py +0 -122
- machineconfig/scripts/python/helpers_devops/cli_share_server.py +0 -104
- machineconfig/scripts/python/helpers_devops/cli_utils.py +0 -221
- machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py +0 -80
- machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +0 -3
- machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_crush.py +0 -37
- machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_gemini.py +0 -44
- machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_qwen.py +0 -43
- machineconfig/scripts/python/helpers_fire/prompt.txt +0 -2
- machineconfig/scripts/python/helpers_fire/template.sh +0 -15
- machineconfig/scripts/python/helpers_navigator/__init__.py +0 -20
- machineconfig/scripts/python/helpers_navigator/command_detail.py +0 -44
- machineconfig/scripts/python/helpers_navigator/command_tree.py +0 -588
- machineconfig/scripts/python/helpers_repos/count_lines_frontend.py +0 -17
- machineconfig/scripts/python/helpers_repos/entrypoint.py +0 -76
- machineconfig/scripts/python/helpers_repos/secure_repo.py +0 -15
- machineconfig/scripts/python/mcfg.py +0 -48
- machineconfig/scripts/python/nw/add_ssh_key.py +0 -148
- machineconfig/scripts/python/nw/devops_add_identity.py +0 -82
- machineconfig/scripts/python/nw/devops_add_ssh_key.py +0 -134
- machineconfig/scripts/python/nw/ssh_debug_linux.py +0 -391
- machineconfig/scripts/python/nw/ssh_debug_windows.py +0 -338
- machineconfig/scripts/python/nw/wsl_windows_transfer.py +0 -66
- machineconfig/scripts/windows/fzfb.ps1 +0 -3
- machineconfig/scripts/windows/fzfg.ps1 +0 -2
- machineconfig/scripts/windows/fzfrga.bat +0 -20
- machineconfig/scripts/windows/mcfgs.ps1 +0 -17
- machineconfig/scripts/windows/mounts/mount_ssh.ps1 +0 -13
- machineconfig/settings/lf/linux/exe/fzf_nano.sh +0 -16
- machineconfig/settings/lf/windows/fzf_edit.ps1 +0 -6
- machineconfig/settings/lf/windows/tst.ps1 +0 -1
- machineconfig/settings/yazi/yazi.toml +0 -4
- machineconfig/setup_linux/apps.sh +0 -66
- machineconfig/setup_linux/others/cli_installation.sh +0 -137
- machineconfig/setup_linux/others/mint_keyboard_shortcuts.sh +0 -30
- machineconfig/setup_linux/ssh/openssh_all.sh +0 -25
- machineconfig/setup_linux/ssh/openssh_wsl.sh +0 -38
- machineconfig/setup_mac/apps.sh +0 -73
- machineconfig/setup_mac/ssh/openssh_setup.sh +0 -114
- machineconfig/setup_windows/apps.ps1 +0 -62
- machineconfig/setup_windows/others/obs.ps1 +0 -4
- machineconfig/setup_windows/ssh/add-sshkey.ps1 +0 -29
- machineconfig/setup_windows/ssh/add_identity.ps1 +0 -11
- machineconfig/setup_windows/ssh/openssh-server.ps1 +0 -37
- machineconfig/utils/installer_utils/installer.py +0 -225
- machineconfig/utils/tst.py +0 -20
- machineconfig-6.82.dist-info/METADATA +0 -82
- machineconfig-6.82.dist-info/RECORD +0 -441
- machineconfig/jobs/installer/{custom_dev → checks}/__init__.py +0 -0
- machineconfig/jobs/installer/linux_scripts/{warp-cli.sh → cloudflare_warp_cli.sh} +0 -0
- machineconfig/{scripts/python/helpers_cloud → jobs/installer/python_scripts}/__init__.py +0 -0
- machineconfig/jobs/installer/{custom_dev → python_scripts}/alacritty.py +0 -0
- machineconfig/jobs/installer/{custom_dev → python_scripts}/bypass_paywall.py +0 -0
- machineconfig/jobs/installer/{custom_dev → python_scripts}/cursor.py +0 -0
- machineconfig/jobs/installer/{custom_dev → python_scripts}/espanso.py +0 -0
- machineconfig/jobs/installer/{custom → python_scripts}/gh.py +0 -0
- machineconfig/jobs/installer/{custom_dev → python_scripts}/goes.py +0 -0
- machineconfig/jobs/installer/{custom_dev → python_scripts}/lvim.py +0 -0
- machineconfig/jobs/installer/{custom_dev → python_scripts}/redis.py +0 -0
- machineconfig/{setup_linux/others → jobs/scripts/bash_scripts}/android.sh +0 -0
- machineconfig/jobs/{installer/linux_scripts → scripts/bash_scripts}/lid.sh +0 -0
- machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_drive +0 -0
- machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_nw_drive +0 -0
- machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_smb +0 -0
- machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_cloud.sh +0 -0
- machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_nfs +0 -0
- machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/start_docker +0 -0
- machineconfig/{scripts → jobs/scripts/powershell_scripts}/Restore-ThunderbirdProfile.ps1 +0 -0
- machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/docker.ps1 +0 -0
- machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nfs.ps1 +0 -0
- machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nw.ps1 +0 -0
- machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_smb.ps1 +0 -0
- machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/power_options.ps1 +0 -0
- machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_cloud.cmd +0 -0
- machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_smb.ps1 +0 -0
- machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/unlock_bitlocker.ps1 +0 -0
- machineconfig/scripts/python/{helpers_croshell → ai/utils}/__init__.py +0 -0
- machineconfig/scripts/python/ai/{solutions/_shared.py → utils/shared.py} +0 -0
- machineconfig/scripts/python/{helpers_devops → graph}/__init__.py +0 -0
- machineconfig/scripts/python/{helpers_devops/themes → helpers}/__init__.py +0 -0
- machineconfig/scripts/python/{env_manager → helpers/helper_env}/__init__.py +0 -0
- machineconfig/scripts/python/{env_manager → helpers/helper_env}/path_manager_backend.py +0 -0
- machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/__init__.py +0 -0
- machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/agentic_frameworks/__init__.py +0 -0
- machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/fire_agents_help_search.py +0 -0
- machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/fire_agents_load_balancer.py +0 -0
- machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents/templates}/template.ps1 +0 -0
- machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_cloud}/__init__.py +0 -0
- machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_helpers.py +1 -1
- /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers5.py +0 -0
- /machineconfig/scripts/python/{helpers_sessions → helpers/helpers_croshell}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/pomodoro.py +0 -0
- /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer.py +0 -0
- /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer_template.py +0 -0
- /machineconfig/scripts/python/{nw → helpers/helpers_devops}/__init__.py +0 -0
- /machineconfig/{setup_windows/wt_and_pwsh → scripts/python/helpers/helpers_devops/themes}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_pwsh_theme.ps1 +0 -0
- /machineconfig/scripts/python/{helpers_devops/themes/choose_starship_theme.ps1 → helpers/helpers_fire_command/__init__.py} +0 -0
- /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/cloud_manager.py +0 -0
- /machineconfig/scripts/python/{helpers_fire_command/fire_jobs_streamlit_helper.py → helpers/helpers_fire_command/f.py} +0 -0
- /machineconfig/{settings/shells/pwsh/profile.ps1 → scripts/python/helpers/helpers_fire_command/fire_jobs_streamlit_helper.py} +0 -0
- /machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/search_bar.py +0 -0
- /machineconfig/{settings/yazi/keymap.toml → scripts/python/helpers/helpers_network/__init__.py} +0 -0
- /machineconfig/scripts/python/{nw → helpers/helpers_network}/mount_nw_drive.py +0 -0
- /machineconfig/scripts/python/{nw → helpers/helpers_network}/onetimeshare.py +0 -0
- /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/sync.py +0 -0
- /machineconfig/{setup_windows/wt_and_pwsh → settings/wt}/set_wt_settings.py +0 -0
- {machineconfig-6.82.dist-info → machineconfig-8.51.dist-info}/WHEEL +0 -0
- {machineconfig-6.82.dist-info → machineconfig-8.51.dist-info}/top_level.txt +0 -0
|
@@ -1,190 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
from typing import TYPE_CHECKING, Annotated
|
|
3
1
|
from git import Repo
|
|
4
|
-
from
|
|
2
|
+
from machineconfig.scripts.python.helpers.helpers_repos.repo_analyzer_1 import count_python_lines, get_default_branch
|
|
5
3
|
from datetime import datetime
|
|
6
|
-
|
|
4
|
+
import polars as pl
|
|
7
5
|
from pathlib import Path
|
|
8
|
-
from
|
|
9
|
-
import typer
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if TYPE_CHECKING:
|
|
13
|
-
from typing import Any, Dict, List, Optional, Union
|
|
14
|
-
import polars as pl
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
app = typer.Typer()
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def count_lines_in_commit(commit: "Any") -> int:
|
|
21
|
-
_total_lines = 0
|
|
22
|
-
for _file in commit.stats.files:
|
|
23
|
-
if str(_file).endswith(".py"):
|
|
24
|
-
_blob = commit.tree / _file
|
|
25
|
-
_total_lines += len(_blob.data_stream.read().decode("utf-8").splitlines())
|
|
26
|
-
return _total_lines
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def count_historical_loc(repo_path: str) -> int:
|
|
30
|
-
repo = Repo(repo_path)
|
|
31
|
-
file_line_counts: "Dict[str, int]" = defaultdict(int)
|
|
32
|
-
total_commits: int = sum(1 for _ in repo.iter_commits())
|
|
33
|
-
print(f"Total commits to process: {total_commits}")
|
|
34
|
-
for i, commit in enumerate(repo.iter_commits(), 1):
|
|
35
|
-
if i % 100 == 0 or i == total_commits:
|
|
36
|
-
print(f"Processing commit {i}/{total_commits} ({i / total_commits:.1%})")
|
|
37
|
-
try:
|
|
38
|
-
# Handle initial commits that have no parents
|
|
39
|
-
if not commit.parents:
|
|
40
|
-
# For initial commit, count all lines in Python files
|
|
41
|
-
for file in commit.stats.files:
|
|
42
|
-
if str(file).endswith(".py"):
|
|
43
|
-
file_line_counts[str(file)] += commit.stats.files[file]["insertions"]
|
|
44
|
-
else:
|
|
45
|
-
# For commits with parents, use stats
|
|
46
|
-
for file in commit.stats.files:
|
|
47
|
-
if str(file).endswith(".py"):
|
|
48
|
-
file_line_counts[str(file)] += commit.stats.files[file]["insertions"]
|
|
49
|
-
except Exception:
|
|
50
|
-
# If stats fail (e.g., corrupted parent), skip this commit
|
|
51
|
-
print(f"Warning: Could not get stats for commit {commit.hexsha[:8]}, skipping")
|
|
52
|
-
continue
|
|
53
|
-
|
|
54
|
-
print(f"\nProcessed files: {len(file_line_counts)}")
|
|
55
|
-
return sum(file_line_counts.values())
|
|
56
|
-
|
|
57
|
-
def count_python_lines(commit: "Any") -> int:
|
|
58
|
-
"""Count total lines in Python files for a specific commit"""
|
|
59
|
-
total_lines = 0
|
|
60
|
-
try:
|
|
61
|
-
for blob in commit.tree.traverse():
|
|
62
|
-
if blob.path.endswith(".py"):
|
|
63
|
-
try:
|
|
64
|
-
content = blob.data_stream.read().decode("utf-8")
|
|
65
|
-
total_lines += len(content.splitlines())
|
|
66
|
-
except Exception as _e:
|
|
67
|
-
continue
|
|
68
|
-
except Exception as _e:
|
|
69
|
-
return 0
|
|
70
|
-
return total_lines
|
|
71
|
-
def get_default_branch(repo: Repo) -> str:
|
|
72
|
-
"""Get the default branch name of the repository"""
|
|
73
|
-
try:
|
|
74
|
-
_ = repo.refs["main"]
|
|
75
|
-
return "main" # First try 'main'
|
|
76
|
-
except IndexError:
|
|
77
|
-
try:
|
|
78
|
-
_ = repo.refs["master"]
|
|
79
|
-
return "master" # Then try 'master'
|
|
80
|
-
except IndexError:
|
|
81
|
-
return repo.head.reference.name # If neither exists, get the branch the HEAD is pointing to
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
@app.command()
|
|
85
|
-
def count_historical(repo_path: Annotated[str, typer.Argument(..., help="Path to the git repository")]):
|
|
86
|
-
"""Count total historical lines of Python code in the repository."""
|
|
87
|
-
print(f"Analyzing repository: {repo_path}")
|
|
88
|
-
total_loc: int = count_historical_loc(repo_path)
|
|
89
|
-
print(f"\nTotal historical lines of Python code: {total_loc}")
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
@app.command()
|
|
93
|
-
def analyze_over_time(repo_path: Annotated[str, typer.Argument(..., help="Path to the git repository")]):
|
|
94
|
-
"""Analyze a git repository to track Python code size over time with visualization."""
|
|
95
|
-
repo: Repo = Repo(repo_path)
|
|
96
|
-
branch_name: str = get_default_branch(repo)
|
|
97
|
-
print(f"🔍 Using branch: {branch_name}")
|
|
98
|
-
commit_data: "List[Dict[str, Any]]" = []
|
|
99
|
-
print("⏳ Analyzing commits...")
|
|
100
|
-
try:
|
|
101
|
-
commits = list(repo.iter_commits(branch_name))
|
|
102
|
-
from datetime import timezone
|
|
103
|
-
|
|
104
|
-
for commit in track(commits, description="Processing commits..."):
|
|
105
|
-
commit_data.append({"hash": commit.hexsha, "dtmExit": datetime.fromtimestamp(commit.committed_date, tz=timezone.utc), "lines": count_python_lines(commit)})
|
|
106
|
-
except Exception as e:
|
|
107
|
-
print(f"❌ Error analyzing commits: {str(e)}")
|
|
108
|
-
return
|
|
109
|
-
|
|
110
|
-
import polars as pl
|
|
111
|
-
import plotly.graph_objects as go
|
|
112
|
-
|
|
113
|
-
df = pl.DataFrame(commit_data)
|
|
114
|
-
df = df.sort("dtmExit")
|
|
115
|
-
# Create interactive plotly figure with dark theme and all bells and whistles
|
|
116
|
-
fig = go.Figure()
|
|
117
|
-
# Add line chart with gradient fill and sparkle effect
|
|
118
|
-
fig.add_trace(go.Scatter(x=df["dtmExit"], y=df["lines"], mode="lines", line={"width": 3, "color": "#00b4ff"}, fill="tozeroy", fillcolor="rgba(0, 180, 255, 0.2)", name="Lines of Code", hovertemplate="<b>Date:</b> %{x}<br><b>Lines:</b> %{y:,}<extra></extra>"))
|
|
119
|
-
# Add markers for significant points (min, max, last)
|
|
120
|
-
min_idx = df["lines"].arg_min()
|
|
121
|
-
max_idx = df["lines"].arg_max()
|
|
122
|
-
min_point = df.slice(min_idx, 1).to_dicts()[0] if min_idx is not None else {}
|
|
123
|
-
max_point = df.slice(max_idx, 1).to_dicts()[0] if max_idx is not None else {}
|
|
124
|
-
last_point = df.slice(-1, 1).to_dicts()[0]
|
|
125
|
-
|
|
126
|
-
# Add markers for significant points
|
|
127
|
-
fig.add_trace(
|
|
128
|
-
go.Scatter(
|
|
129
|
-
x=[min_point["dtmExit"], max_point["dtmExit"], last_point["dtmExit"]],
|
|
130
|
-
y=[min_point["lines"], max_point["lines"], last_point["lines"]],
|
|
131
|
-
mode="markers",
|
|
132
|
-
marker={"size": [10, 14, 12], "color": ["#ff4f4f", "#4fff4f", "#4f4fff"], "line": {"width": 2, "color": "white"}, "symbol": ["circle", "star", "diamond"]},
|
|
133
|
-
name="Key Points",
|
|
134
|
-
hovertemplate="<b>%{text}</b><br>Date: %{x}<br>Lines: %{y:,}<extra></extra>",
|
|
135
|
-
text=[f"🔽 Min: {min_point['lines']:,} lines", f"🔼 Max: {max_point['lines']:,} lines", f"📊 Current: {last_point['lines']:,} lines"],
|
|
136
|
-
)
|
|
137
|
-
)
|
|
6
|
+
from typing import cast, TypedDict
|
|
138
7
|
|
|
139
|
-
# Add annotation only for current point
|
|
140
|
-
# annotations = [
|
|
141
|
-
# {"x": last_point['date'], "y": last_point['lines'], "text": f"📊 Current: {last_point['lines']:,} lines", "showarrow": True, "arrowhead": 2, "arrowsize": 1,
|
|
142
|
-
# "arrowwidth": 2, "arrowcolor": "#ffffff", "font": {"size": 14, "color": "#ffffff"}, "bgcolor": "#00b4ff", "bordercolor": "#ffffff",
|
|
143
|
-
# "borderwidth": 1, "borderpad": 4, "ax": 40, "ay": -40}
|
|
144
|
-
# ]
|
|
145
8
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
xaxis_title="Date 📅",
|
|
150
|
-
yaxis_title="Lines of Code 📝",
|
|
151
|
-
hovermode="closest",
|
|
152
|
-
template="plotly_dark",
|
|
153
|
-
plot_bgcolor="rgba(25, 25, 35, 1)",
|
|
154
|
-
paper_bgcolor="rgba(15, 15, 25, 1)",
|
|
155
|
-
font={"family": "Arial, sans-serif", "size": 14, "color": "white"}, # annotations=annotations,
|
|
156
|
-
autosize=True,
|
|
157
|
-
height=700,
|
|
158
|
-
margin={"l": 80, "r": 80, "t": 100, "b": 80},
|
|
159
|
-
xaxis={"showgrid": True, "gridcolor": "rgba(80, 80, 100, 0.2)", "showline": True, "linecolor": "rgba(200, 200, 255, 0.2)", "tickfont": {"size": 12}},
|
|
160
|
-
yaxis={"showgrid": True, "gridcolor": "rgba(80, 80, 100, 0.2)", "showline": True, "linecolor": "rgba(200, 200, 255, 0.2)", "tickformat": ",", "tickfont": {"size": 12}},
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
# Add range slider for date selection
|
|
164
|
-
fig.update_xaxes(rangeslider_visible=True, rangeslider_thickness=0.05)
|
|
165
|
-
|
|
166
|
-
# Save as interactive HTML and static image
|
|
167
|
-
plot_dir = Path.home().joinpath("tmp_results", "tmp_images", Path(repo_path).name)
|
|
168
|
-
plot_dir.mkdir(parents=True, exist_ok=True)
|
|
9
|
+
class FileDataRow(TypedDict):
|
|
10
|
+
filename: str
|
|
11
|
+
lines: int
|
|
169
12
|
|
|
170
|
-
html_path = plot_dir.joinpath("code_size_evolution.html")
|
|
171
|
-
png_path = plot_dir.joinpath("code_size_evolution.png")
|
|
172
13
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
print(f"🖼️ Static image saved as {png_path}")
|
|
178
|
-
# Print statistics
|
|
179
|
-
print("\n📊 Repository Statistics:")
|
|
180
|
-
print(f"📚 Total commits analyzed: {len(df)}")
|
|
181
|
-
print(f"🔙 Initial line count: {df['lines'][-1]:,}")
|
|
182
|
-
print(f"🔜 Final line count: {df['lines'][0]:,}")
|
|
183
|
-
print(f"📈 Net change: {df['lines'][0] - df['lines'][-1]:,} lines")
|
|
14
|
+
class CommitDataRow(TypedDict):
|
|
15
|
+
hash: str
|
|
16
|
+
dtmExit: datetime
|
|
17
|
+
lines: int
|
|
184
18
|
|
|
185
19
|
|
|
186
|
-
def
|
|
187
|
-
import polars as pl
|
|
20
|
+
def print_python_files_by_size_impl(repo_path: str) -> pl.DataFrame | Exception:
|
|
188
21
|
import plotly.graph_objects as go
|
|
189
22
|
import plotly.express as px
|
|
190
23
|
|
|
@@ -193,7 +26,7 @@ def _print_python_files_by_size_impl(repo_path: str) -> "Union[pl.DataFrame, Exc
|
|
|
193
26
|
if not os.path.exists(repo_path):
|
|
194
27
|
return ValueError(f"Repository path does not exist: {repo_path}")
|
|
195
28
|
# Initialize data storage
|
|
196
|
-
file_data:
|
|
29
|
+
file_data: list[FileDataRow] = []
|
|
197
30
|
|
|
198
31
|
# Walk through the repository
|
|
199
32
|
for root, _, files in os.walk(repo_path):
|
|
@@ -227,13 +60,26 @@ def _print_python_files_by_size_impl(repo_path: str) -> "Union[pl.DataFrame, Exc
|
|
|
227
60
|
df = df.sort("lines", descending=True)
|
|
228
61
|
df = df.filter(pl.col("lines") > 0) # Filter out empty files
|
|
229
62
|
|
|
63
|
+
from rich.console import Console
|
|
64
|
+
from rich.table import Table
|
|
65
|
+
|
|
230
66
|
# Add total count
|
|
231
67
|
total_lines = int(df["lines"].sum())
|
|
232
68
|
file_count: int = len(df)
|
|
233
|
-
|
|
69
|
+
console = Console()
|
|
234
70
|
# Print the DataFrame
|
|
235
|
-
print("\n📊 Python Files Line Count (sorted max to min):")
|
|
236
|
-
|
|
71
|
+
console.print("\n📊 Python Files Line Count (sorted max to min):")
|
|
72
|
+
|
|
73
|
+
table = Table(show_header=True, header_style="bold cyan")
|
|
74
|
+
table.add_column("#", justify="right")
|
|
75
|
+
table.add_column("File", overflow="fold")
|
|
76
|
+
table.add_column("Lines", justify="right")
|
|
77
|
+
|
|
78
|
+
for idx, row in enumerate(df.iter_rows(named=True), 1):
|
|
79
|
+
typed_row = cast(FileDataRow, row)
|
|
80
|
+
table.add_row(str(idx), typed_row["filename"], f"{typed_row['lines']:,}")
|
|
81
|
+
|
|
82
|
+
console.print(table)
|
|
237
83
|
print(f"\n📁 Total Python files: {file_count}")
|
|
238
84
|
print(f"📝 Total lines of Python code: {total_lines:,}")
|
|
239
85
|
|
|
@@ -283,7 +129,7 @@ def _print_python_files_by_size_impl(repo_path: str) -> "Union[pl.DataFrame, Exc
|
|
|
283
129
|
)
|
|
284
130
|
|
|
285
131
|
# Define pie chart figure before conditionally using it
|
|
286
|
-
fig2:
|
|
132
|
+
fig2: go.Figure | None = None
|
|
287
133
|
|
|
288
134
|
# Add pie chart showing distribution
|
|
289
135
|
if len(df) > top_n:
|
|
@@ -335,14 +181,133 @@ def _print_python_files_by_size_impl(repo_path: str) -> "Union[pl.DataFrame, Exc
|
|
|
335
181
|
return Exception(f"❌ Error analyzing repository: {str(e)}")
|
|
336
182
|
|
|
337
183
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
184
|
+
def analyze_over_time(repo_path: str):
|
|
185
|
+
"""Analyze a git repository to track Python code size over time with visualization."""
|
|
186
|
+
repo: Repo = Repo(repo_path)
|
|
187
|
+
branch_name: str = get_default_branch(repo)
|
|
188
|
+
print(f"🔍 Using branch: {branch_name}")
|
|
189
|
+
commit_data: list[CommitDataRow] = []
|
|
190
|
+
print("⏳ Analyzing commits...")
|
|
191
|
+
try:
|
|
192
|
+
commits = list(repo.iter_commits(branch_name))
|
|
193
|
+
from datetime import timezone
|
|
194
|
+
from rich.progress import track
|
|
195
|
+
for commit in track(commits, description="Processing commits..."):
|
|
196
|
+
lines, _files = count_python_lines(commit)
|
|
197
|
+
commit_data.append({"hash": commit.hexsha, "dtmExit": datetime.fromtimestamp(commit.committed_date, tz=timezone.utc), "lines": lines})
|
|
198
|
+
except Exception as e:
|
|
199
|
+
print(f"❌ Error analyzing commits: {str(e)}")
|
|
344
200
|
return
|
|
345
201
|
|
|
202
|
+
import polars as pl
|
|
203
|
+
import plotly.graph_objects as go
|
|
346
204
|
|
|
347
|
-
|
|
348
|
-
|
|
205
|
+
df = pl.DataFrame(commit_data)
|
|
206
|
+
df = df.sort("dtmExit")
|
|
207
|
+
# Create interactive plotly figure with dark theme and all bells and whistles
|
|
208
|
+
fig = go.Figure()
|
|
209
|
+
# Add line chart with gradient fill and sparkle effect
|
|
210
|
+
fig.add_trace(go.Scatter(x=df["dtmExit"], y=df["lines"], mode="lines", line={"width": 3, "color": "#00b4ff"}, fill="tozeroy", fillcolor="rgba(0, 180, 255, 0.2)", name="Lines of Code", hovertemplate="<b>Date:</b> %{x}<br><b>Lines:</b> %{y:,}<extra></extra>"))
|
|
211
|
+
# Add markers for significant points (min, max, last)
|
|
212
|
+
min_idx = df["lines"].arg_min()
|
|
213
|
+
max_idx = df["lines"].arg_max()
|
|
214
|
+
last_point = cast(CommitDataRow, df.slice(-1, 1).to_dicts()[0])
|
|
215
|
+
|
|
216
|
+
marker_x: list[datetime] = []
|
|
217
|
+
marker_y: list[int] = []
|
|
218
|
+
marker_sizes: list[int] = []
|
|
219
|
+
marker_colors: list[str] = []
|
|
220
|
+
marker_symbols: list[str] = []
|
|
221
|
+
marker_texts: list[str] = []
|
|
222
|
+
|
|
223
|
+
if min_idx is not None:
|
|
224
|
+
min_point = cast(CommitDataRow, df.slice(min_idx, 1).to_dicts()[0])
|
|
225
|
+
marker_x.append(min_point["dtmExit"])
|
|
226
|
+
marker_y.append(min_point["lines"])
|
|
227
|
+
marker_sizes.append(10)
|
|
228
|
+
marker_colors.append("#ff4f4f")
|
|
229
|
+
marker_symbols.append("circle")
|
|
230
|
+
marker_texts.append(f"🔽 Min: {min_point['lines']:,} lines")
|
|
231
|
+
|
|
232
|
+
if max_idx is not None:
|
|
233
|
+
max_point = cast(CommitDataRow, df.slice(max_idx, 1).to_dicts()[0])
|
|
234
|
+
marker_x.append(max_point["dtmExit"])
|
|
235
|
+
marker_y.append(max_point["lines"])
|
|
236
|
+
marker_sizes.append(14)
|
|
237
|
+
marker_colors.append("#4fff4f")
|
|
238
|
+
marker_symbols.append("star")
|
|
239
|
+
marker_texts.append(f"🔼 Max: {max_point['lines']:,} lines")
|
|
240
|
+
|
|
241
|
+
marker_x.append(last_point["dtmExit"])
|
|
242
|
+
marker_y.append(last_point["lines"])
|
|
243
|
+
marker_sizes.append(12)
|
|
244
|
+
marker_colors.append("#4f4fff")
|
|
245
|
+
marker_symbols.append("diamond")
|
|
246
|
+
marker_texts.append(f"📊 Current: {last_point['lines']:,} lines")
|
|
247
|
+
|
|
248
|
+
# Add markers for significant points
|
|
249
|
+
fig.add_trace(
|
|
250
|
+
go.Scatter(
|
|
251
|
+
x=marker_x,
|
|
252
|
+
y=marker_y,
|
|
253
|
+
mode="markers",
|
|
254
|
+
marker={"size": marker_sizes, "color": marker_colors, "line": {"width": 2, "color": "white"}, "symbol": marker_symbols},
|
|
255
|
+
name="Key Points",
|
|
256
|
+
hovertemplate="<b>%{text}</b><br>Date: %{x}<br>Lines: %{y:,}<extra></extra>",
|
|
257
|
+
text=marker_texts,
|
|
258
|
+
)
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
# Add annotation only for current point
|
|
262
|
+
# annotations = [
|
|
263
|
+
# {"x": last_point['date'], "y": last_point['lines'], "text": f"📊 Current: {last_point['lines']:,} lines", "showarrow": True, "arrowhead": 2, "arrowsize": 1,
|
|
264
|
+
# "arrowwidth": 2, "arrowcolor": "#ffffff", "font": {"size": 14, "color": "#ffffff"}, "bgcolor": "#00b4ff", "bordercolor": "#ffffff",
|
|
265
|
+
# "borderwidth": 1, "borderpad": 4, "ax": 40, "ay": -40}
|
|
266
|
+
# ]
|
|
267
|
+
|
|
268
|
+
# Update layout with dark theme and customizations
|
|
269
|
+
fig.update_layout(
|
|
270
|
+
title={"text": "✨ Python Code Base Size Over Time ✨", "y": 0.95, "x": 0.5, "xanchor": "center", "yanchor": "top", "font": {"size": 24, "color": "white"}},
|
|
271
|
+
xaxis_title="Date 📅",
|
|
272
|
+
yaxis_title="Lines of Code 📝",
|
|
273
|
+
hovermode="closest",
|
|
274
|
+
template="plotly_dark",
|
|
275
|
+
plot_bgcolor="rgba(25, 25, 35, 1)",
|
|
276
|
+
paper_bgcolor="rgba(15, 15, 25, 1)",
|
|
277
|
+
font={"family": "Arial, sans-serif", "size": 14, "color": "white"}, # annotations=annotations,
|
|
278
|
+
autosize=True,
|
|
279
|
+
height=700,
|
|
280
|
+
margin={"l": 80, "r": 80, "t": 100, "b": 80},
|
|
281
|
+
xaxis={"showgrid": True, "gridcolor": "rgba(80, 80, 100, 0.2)", "showline": True, "linecolor": "rgba(200, 200, 255, 0.2)", "tickfont": {"size": 12}},
|
|
282
|
+
yaxis={"showgrid": True, "gridcolor": "rgba(80, 80, 100, 0.2)", "showline": True, "linecolor": "rgba(200, 200, 255, 0.2)", "tickformat": ",", "tickfont": {"size": 12}},
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
# Add range slider for date selection
|
|
286
|
+
fig.update_xaxes(rangeslider_visible=True, rangeslider_thickness=0.05)
|
|
287
|
+
|
|
288
|
+
# Save as interactive HTML and static image
|
|
289
|
+
plot_dir = Path.home().joinpath("tmp_results", "tmp_images", Path(repo_path).name)
|
|
290
|
+
plot_dir.mkdir(parents=True, exist_ok=True)
|
|
291
|
+
|
|
292
|
+
html_path = plot_dir.joinpath("code_size_evolution.html")
|
|
293
|
+
png_path = plot_dir.joinpath("code_size_evolution.png")
|
|
294
|
+
|
|
295
|
+
try:
|
|
296
|
+
fig.write_html(html_path, include_plotlyjs="cdn")
|
|
297
|
+
except Exception as e:
|
|
298
|
+
print(f"❌ Error saving HTML plot: {str(e)}")
|
|
299
|
+
try:
|
|
300
|
+
fig.write_image(png_path, width=1200, height=700, scale=2)
|
|
301
|
+
except Exception as e:
|
|
302
|
+
print(f"❌ Error saving PNG plot: {str(e)}")
|
|
303
|
+
|
|
304
|
+
print(f"🖼️ Interactive plot saved as {html_path}")
|
|
305
|
+
print(f"🖼️ Static image saved as {png_path}")
|
|
306
|
+
# Print statistics
|
|
307
|
+
print("\n📊 Repository Statistics:")
|
|
308
|
+
print(f"📚 Total commits analyzed: {len(df)}")
|
|
309
|
+
initial_lines = int(df['lines'][-1])
|
|
310
|
+
final_lines = int(df['lines'][0])
|
|
311
|
+
print(f"🔙 Initial line count: {initial_lines:,}")
|
|
312
|
+
print(f"🔜 Final line count: {final_lines:,}")
|
|
313
|
+
print(f"📈 Net change: {final_lines - initial_lines:,} lines")
|
|
@@ -246,12 +246,6 @@ def update_repository(repo: git.Repo, auto_uv_sync: bool, allow_password_prompt:
|
|
|
246
246
|
result["permissions_updated"] = True
|
|
247
247
|
print(f"✅ Set permissions for {linux_jobs_path}")
|
|
248
248
|
|
|
249
|
-
lf_exe_path = repo_path / "src" / "machineconfig" / "settings" / "lf" / "linux" / "exe"
|
|
250
|
-
if lf_exe_path.exists():
|
|
251
|
-
set_permissions_recursive(lf_exe_path)
|
|
252
|
-
result["permissions_updated"] = True
|
|
253
|
-
print(f"✅ Set permissions for {lf_exe_path}")
|
|
254
|
-
|
|
255
249
|
# Run uv sync if dependencies changed and auto_sync is enabled
|
|
256
250
|
if result["dependencies_changed"] and auto_uv_sync:
|
|
257
251
|
result["uv_sync_ran"] = True
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
|
|
2
|
+
import ast
|
|
3
|
+
import os
|
|
4
|
+
from typing import TypedDict
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class SymbolInfo(TypedDict):
|
|
8
|
+
"""Represents a symbol (module, class, or function) in the repository."""
|
|
9
|
+
type: str
|
|
10
|
+
name: str
|
|
11
|
+
path: str
|
|
12
|
+
# line: int | None
|
|
13
|
+
# column: int | None
|
|
14
|
+
docstring: str
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _get_docstring(node: ast.AsyncFunctionDef | ast.FunctionDef | ast.ClassDef | ast.Module) -> str:
|
|
18
|
+
"""Extract docstring from an AST node."""
|
|
19
|
+
return ast.get_docstring(node) or ""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _extract_symbols(tree: ast.AST, module_path: str, source: str) -> list[SymbolInfo]:
|
|
23
|
+
"""Extract symbols from an AST tree."""
|
|
24
|
+
symbols: list[SymbolInfo] = []
|
|
25
|
+
|
|
26
|
+
for node in ast.walk(tree):
|
|
27
|
+
if isinstance(node, ast.FunctionDef | ast.AsyncFunctionDef):
|
|
28
|
+
symbol: SymbolInfo = {
|
|
29
|
+
"type": "function",
|
|
30
|
+
"name": node.name,
|
|
31
|
+
"path": f"{module_path}.{node.name}",
|
|
32
|
+
"docstring": _get_docstring(node),
|
|
33
|
+
}
|
|
34
|
+
symbols.append(symbol)
|
|
35
|
+
elif isinstance(node, ast.ClassDef):
|
|
36
|
+
symbol: SymbolInfo = {
|
|
37
|
+
"type": "class",
|
|
38
|
+
"name": node.name,
|
|
39
|
+
"path": f"{module_path}.{node.name}",
|
|
40
|
+
"docstring": _get_docstring(node),
|
|
41
|
+
}
|
|
42
|
+
symbols.append(symbol)
|
|
43
|
+
|
|
44
|
+
return symbols
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def get_repo_symbols(repo_path: str) -> list[SymbolInfo]:
|
|
48
|
+
skip_dirs = {'.venv', 'venv', '__pycache__', '.mypy_cache', '.pytest_cache', '.git'}
|
|
49
|
+
results: list[SymbolInfo] = []
|
|
50
|
+
counter: int = 0
|
|
51
|
+
for root, dirs, files in os.walk(repo_path):
|
|
52
|
+
dirs[:] = [d for d in dirs if d not in skip_dirs and not d.startswith('.')]
|
|
53
|
+
for file in files:
|
|
54
|
+
if not file.endswith(".py"):
|
|
55
|
+
continue
|
|
56
|
+
file_path = os.path.join(root, file)
|
|
57
|
+
module_path = (
|
|
58
|
+
os.path.relpath(file_path, repo_path)
|
|
59
|
+
.replace(os.sep, ".")
|
|
60
|
+
.removesuffix(".py")
|
|
61
|
+
)
|
|
62
|
+
try:
|
|
63
|
+
if counter % 100 == 0: print(f"🔍 Parsing {counter}: {file_path}...")
|
|
64
|
+
with open(file_path, encoding="utf-8") as f:
|
|
65
|
+
source = f.read()
|
|
66
|
+
tree = ast.parse(source, filename=file_path)
|
|
67
|
+
symbols = _extract_symbols(tree, module_path, source)
|
|
68
|
+
results.extend(symbols)
|
|
69
|
+
except Exception as e:
|
|
70
|
+
print(f"⚠️ Error parsing {file_path}: {e}")
|
|
71
|
+
continue
|
|
72
|
+
counter += 1
|
|
73
|
+
|
|
74
|
+
return results
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def generate_qrcode_grid(
|
|
7
|
+
strings: list[str],
|
|
8
|
+
output_path: str,
|
|
9
|
+
per_row: int = 3,
|
|
10
|
+
qr_size: int = 200,
|
|
11
|
+
label_height: int = 30,
|
|
12
|
+
padding: int = 20,
|
|
13
|
+
label_max_chars: int = 25,
|
|
14
|
+
format: Literal["svg", "png"] = "svg",
|
|
15
|
+
) -> str:
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
if not strings:
|
|
18
|
+
raise ValueError("strings list cannot be empty")
|
|
19
|
+
|
|
20
|
+
output_path_obj = Path(output_path)
|
|
21
|
+
output_path_obj.parent.mkdir(parents=True, exist_ok=True)
|
|
22
|
+
|
|
23
|
+
if format == "svg":
|
|
24
|
+
return _generate_svg(strings, output_path, per_row, qr_size, label_height, padding, label_max_chars)
|
|
25
|
+
elif format == "png":
|
|
26
|
+
return _generate_png(strings, output_path, per_row, qr_size, label_height, padding, label_max_chars)
|
|
27
|
+
else:
|
|
28
|
+
raise ValueError(f"Unsupported format: {format}")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _generate_svg(
|
|
32
|
+
strings: list[str],
|
|
33
|
+
output_path: str,
|
|
34
|
+
per_row: int,
|
|
35
|
+
qr_size: int,
|
|
36
|
+
label_height: int,
|
|
37
|
+
padding: int,
|
|
38
|
+
label_max_chars: int,
|
|
39
|
+
) -> str:
|
|
40
|
+
num_items = len(strings)
|
|
41
|
+
num_rows = (num_items + per_row - 1) // per_row
|
|
42
|
+
|
|
43
|
+
cell_width = qr_size
|
|
44
|
+
cell_height = qr_size + label_height
|
|
45
|
+
total_width = per_row * cell_width + (per_row + 1) * padding
|
|
46
|
+
total_height = num_rows * cell_height + (num_rows + 1) * padding
|
|
47
|
+
|
|
48
|
+
from xml.etree import ElementTree as ET
|
|
49
|
+
|
|
50
|
+
import qrcode
|
|
51
|
+
svg_root = ET.Element(
|
|
52
|
+
"svg",
|
|
53
|
+
xmlns="http://www.w3.org/2000/svg",
|
|
54
|
+
width=str(total_width),
|
|
55
|
+
height=str(total_height),
|
|
56
|
+
viewBox=f"0 0 {total_width} {total_height}",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
_bg_rect = ET.SubElement(svg_root, "rect", width=str(total_width), height=str(total_height), fill="white")
|
|
60
|
+
|
|
61
|
+
for idx, text in enumerate(strings):
|
|
62
|
+
row = idx // per_row
|
|
63
|
+
col = idx % per_row
|
|
64
|
+
|
|
65
|
+
x_offset = padding + col * (cell_width + padding)
|
|
66
|
+
y_offset = padding + row * (cell_height + padding)
|
|
67
|
+
|
|
68
|
+
qr = qrcode.QRCode(version=1, error_correction=qrcode.ERROR_CORRECT_L, box_size=10, border=2, image_factory=qrcode.image.svg.SvgPathImage) # type: ignore
|
|
69
|
+
qr.add_data(text)
|
|
70
|
+
qr.make(fit=True)
|
|
71
|
+
|
|
72
|
+
qr_img = qr.make_image()
|
|
73
|
+
qr_svg_string = qr_img.to_string(encoding="unicode")
|
|
74
|
+
|
|
75
|
+
qr_tree = ET.fromstring(qr_svg_string)
|
|
76
|
+
|
|
77
|
+
group = ET.SubElement(svg_root, "g", transform=f"translate({x_offset}, {y_offset})")
|
|
78
|
+
|
|
79
|
+
qr_group = ET.SubElement(group, "g")
|
|
80
|
+
for child in qr_tree:
|
|
81
|
+
qr_group.append(child)
|
|
82
|
+
|
|
83
|
+
label_text = text[:label_max_chars] if len(text) > label_max_chars else text
|
|
84
|
+
text_y = qr_size + label_height // 2
|
|
85
|
+
|
|
86
|
+
text_elem = ET.SubElement(
|
|
87
|
+
group,
|
|
88
|
+
"text",
|
|
89
|
+
x=str(qr_size // 2),
|
|
90
|
+
y=str(text_y),
|
|
91
|
+
fill="black",
|
|
92
|
+
attrib={
|
|
93
|
+
"font-family": "monospace",
|
|
94
|
+
"font-size": "12",
|
|
95
|
+
"text-anchor": "middle",
|
|
96
|
+
"dominant-baseline": "middle",
|
|
97
|
+
},
|
|
98
|
+
)
|
|
99
|
+
text_elem.text = label_text
|
|
100
|
+
|
|
101
|
+
tree = ET.ElementTree(svg_root)
|
|
102
|
+
ET.indent(tree, space=" ")
|
|
103
|
+
tree.write(output_path, encoding="unicode", xml_declaration=True)
|
|
104
|
+
|
|
105
|
+
return output_path
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _generate_png(
|
|
109
|
+
strings: list[str],
|
|
110
|
+
output_path: str,
|
|
111
|
+
per_row: int,
|
|
112
|
+
qr_size: int,
|
|
113
|
+
label_height: int,
|
|
114
|
+
padding: int,
|
|
115
|
+
label_max_chars: int,
|
|
116
|
+
) -> str:
|
|
117
|
+
num_items = len(strings)
|
|
118
|
+
num_rows = (num_items + per_row - 1) // per_row
|
|
119
|
+
|
|
120
|
+
cell_width = qr_size
|
|
121
|
+
cell_height = qr_size + label_height
|
|
122
|
+
total_width = per_row * cell_width + (per_row + 1) * padding
|
|
123
|
+
total_height = num_rows * cell_height + (num_rows + 1) * padding
|
|
124
|
+
|
|
125
|
+
import qrcode
|
|
126
|
+
import qrcode.image.pil
|
|
127
|
+
from PIL import Image, ImageDraw, ImageFont
|
|
128
|
+
img = Image.new("RGB", (total_width, total_height), color="white")
|
|
129
|
+
draw = ImageDraw.Draw(img)
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", 12)
|
|
133
|
+
except OSError:
|
|
134
|
+
try:
|
|
135
|
+
font = ImageFont.truetype("arial.ttf", 12)
|
|
136
|
+
except OSError:
|
|
137
|
+
font = ImageFont.load_default()
|
|
138
|
+
|
|
139
|
+
for idx, text in enumerate(strings):
|
|
140
|
+
row = idx // per_row
|
|
141
|
+
col = idx % per_row
|
|
142
|
+
|
|
143
|
+
x_offset = padding + col * (cell_width + padding)
|
|
144
|
+
y_offset = padding + row * (cell_height + padding)
|
|
145
|
+
|
|
146
|
+
qr = qrcode.QRCode(version=1, error_correction=qrcode.ERROR_CORRECT_L, box_size=10, border=2, image_factory=qrcode.image.pil.PilImage)
|
|
147
|
+
qr.add_data(text)
|
|
148
|
+
qr.make(fit=True)
|
|
149
|
+
|
|
150
|
+
qr_img = qr.make_image(fill_color="black", back_color="white")
|
|
151
|
+
qr_img_resized = qr_img.resize((qr_size, qr_size), Image.Resampling.LANCZOS)
|
|
152
|
+
|
|
153
|
+
img.paste(qr_img_resized, (x_offset, y_offset))
|
|
154
|
+
|
|
155
|
+
label_text = text[:label_max_chars] if len(text) > label_max_chars else text
|
|
156
|
+
|
|
157
|
+
bbox = draw.textbbox((0, 0), label_text, font=font)
|
|
158
|
+
text_width = bbox[2] - bbox[0]
|
|
159
|
+
text_x = x_offset + (qr_size - text_width) // 2
|
|
160
|
+
text_y = y_offset + qr_size + label_height // 2 - 6
|
|
161
|
+
|
|
162
|
+
draw.text((text_x, text_y), label_text, fill="black", font=font)
|
|
163
|
+
|
|
164
|
+
img.save(output_path, format="PNG")
|
|
165
|
+
|
|
166
|
+
return output_path
|