machineconfig 7.50__py3-none-any.whl → 8.12__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/cluster/remote/cloud_manager.py +1 -1
- machineconfig/cluster/sessions_managers/utils/maker.py +23 -11
- machineconfig/cluster/sessions_managers/wt_local_manager.py +22 -19
- machineconfig/cluster/sessions_managers/wt_remote_manager.py +3 -1
- machineconfig/cluster/sessions_managers/zellij_local_manager.py +3 -1
- machineconfig/cluster/sessions_managers/zellij_remote_manager.py +3 -2
- machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +2 -2
- machineconfig/jobs/installer/installer_data.json +1185 -165
- machineconfig/jobs/installer/linux_scripts/q.sh +10 -7
- machineconfig/jobs/installer/linux_scripts/redis.sh +1 -0
- machineconfig/jobs/installer/package_groups.py +52 -84
- machineconfig/jobs/installer/powershell_scripts/install_fonts.ps1 +129 -34
- machineconfig/jobs/installer/{custom → python_scripts}/boxes.py +2 -2
- 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 +4 -1
- machineconfig/jobs/installer/{custom_dev → python_scripts}/dubdb_adbc.py +1 -1
- machineconfig/jobs/installer/{custom → python_scripts}/hx.py +16 -12
- machineconfig/jobs/installer/{custom_dev → python_scripts}/nerdfont.py +2 -2
- machineconfig/jobs/installer/{custom_dev → python_scripts}/nerfont_windows_helper.py +27 -22
- machineconfig/jobs/installer/python_scripts/sysabc.py +139 -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 +121 -0
- machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_nfs +0 -1
- 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 +25 -0
- machineconfig/logger.py +0 -1
- machineconfig/profile/create_helper.py +21 -22
- machineconfig/profile/create_links_export.py +25 -11
- machineconfig/profile/create_shell_profile.py +14 -3
- machineconfig/profile/mapper.toml +8 -6
- machineconfig/scripts/__init__.py +0 -4
- machineconfig/scripts/linux/wrap_mcfg +20 -21
- machineconfig/scripts/python/agents.py +74 -50
- machineconfig/scripts/python/ai/initai.py +1 -1
- 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.sh +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 +5 -5
- machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +4 -0
- machineconfig/scripts/python/ai/solutions/copilot/instructions/python/watch_exec.prompt.md +20 -0
- machineconfig/scripts/python/ai/solutions/generic.py +1 -1
- machineconfig/scripts/python/ai/{generate_files.py → utils/generate_files.py} +2 -2
- machineconfig/scripts/python/cloud.py +6 -6
- machineconfig/scripts/python/croshell.py +67 -60
- machineconfig/scripts/python/devops.py +41 -21
- machineconfig/scripts/python/devops_navigator.py +0 -4
- machineconfig/scripts/python/env_manager/env_manager_tui.py +204 -0
- machineconfig/scripts/python/env_manager/path_manager_tui.py +1 -1
- machineconfig/scripts/python/fire_jobs.py +95 -67
- machineconfig/scripts/python/ftpx.py +44 -17
- machineconfig/scripts/python/helpers/ast_search.py +74 -0
- machineconfig/scripts/python/helpers/qr_code.py +166 -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 +1 -1
- machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.py +9 -7
- machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_gemini.py +21 -8
- machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_qwen.py +0 -12
- machineconfig/scripts/python/helpers_agents/fire_agents_help_launch.py +30 -11
- machineconfig/scripts/python/helpers_agents/fire_agents_helper_types.py +9 -2
- machineconfig/scripts/python/helpers_agents/privacy/configs/aichat/config.yaml +5 -0
- machineconfig/scripts/python/helpers_agents/privacy/configs/aider/.aider.conf.yml +2 -0
- machineconfig/scripts/python/helpers_agents/privacy/configs/copilot/config.yml +1 -0
- machineconfig/scripts/python/helpers_agents/privacy/configs/crush/crush.json +10 -0
- machineconfig/scripts/python/helpers_agents/privacy/configs/gemini/settings.json +12 -0
- machineconfig/scripts/python/helpers_agents/privacy/privacy.py +109 -0
- machineconfig/scripts/python/helpers_agents/templates/prompt.txt +8 -4
- machineconfig/scripts/python/helpers_agents/templates/template.sh +18 -8
- machineconfig/scripts/python/helpers_cloud/cloud_copy.py +28 -21
- machineconfig/scripts/python/helpers_cloud/cloud_helpers.py +1 -1
- machineconfig/scripts/python/helpers_cloud/cloud_mount.py +19 -17
- machineconfig/scripts/python/helpers_cloud/cloud_sync.py +8 -7
- machineconfig/scripts/python/helpers_croshell/crosh.py +3 -3
- machineconfig/scripts/python/helpers_croshell/start_slidev.py +6 -7
- machineconfig/scripts/python/helpers_devops/cli_config.py +19 -25
- machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +22 -13
- machineconfig/scripts/python/helpers_devops/cli_nw.py +113 -26
- machineconfig/scripts/python/helpers_devops/cli_repos.py +37 -11
- machineconfig/scripts/python/helpers_devops/cli_self.py +84 -39
- machineconfig/scripts/python/helpers_devops/cli_share_file.py +9 -9
- machineconfig/scripts/python/helpers_devops/cli_share_server.py +13 -12
- machineconfig/scripts/python/helpers_devops/{cli_terminal.py → cli_share_terminal.py} +15 -17
- machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py +4 -4
- machineconfig/scripts/python/helpers_devops/devops_status.py +7 -19
- machineconfig/scripts/python/helpers_devops/run_script.py +168 -0
- machineconfig/scripts/python/helpers_devops/themes/choose_wezterm_theme.py +1 -1
- machineconfig/scripts/python/helpers_fire_command/file_wrangler.py +2 -19
- machineconfig/scripts/python/helpers_fire_command/fire_jobs_args_helper.py +1 -0
- machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +25 -15
- machineconfig/scripts/python/helpers_msearch/scripts_linux/fzfg +3 -3
- machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfg.ps1 +58 -1
- machineconfig/scripts/python/helpers_navigator/command_tree.py +50 -18
- machineconfig/scripts/python/helpers_network/address.py +176 -0
- machineconfig/scripts/python/helpers_network/address_switch.py +78 -0
- machineconfig/scripts/python/{nw → helpers_network}/mount_nfs.py +2 -2
- machineconfig/scripts/python/{nw → helpers_network}/mount_ssh.py +1 -1
- machineconfig/scripts/python/{nw/devops_add_identity.py → helpers_network/ssh_add_identity.py} +35 -1
- machineconfig/scripts/python/{nw/devops_add_ssh_key.py → helpers_network/ssh_add_ssh_key.py} +26 -7
- machineconfig/scripts/python/{nw → helpers_network}/ssh_debug_linux.py +7 -7
- machineconfig/scripts/python/{nw → helpers_network}/ssh_debug_windows.py +4 -4
- machineconfig/scripts/python/helpers_repos/clone.py +0 -1
- machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +13 -5
- machineconfig/scripts/python/helpers_repos/entrypoint.py +2 -1
- machineconfig/scripts/python/helpers_repos/record.py +2 -1
- machineconfig/scripts/python/helpers_repos/repo_analyzer_1.py +160 -0
- machineconfig/scripts/python/helpers_repos/{count_lines.py → repo_analyzer_2.py} +113 -192
- machineconfig/scripts/python/helpers_sessions/sessions_multiprocess.py +19 -13
- machineconfig/scripts/python/helpers_utils/download.py +150 -0
- machineconfig/scripts/python/helpers_utils/pdf.py +96 -0
- machineconfig/scripts/python/helpers_utils/python.py +187 -0
- machineconfig/scripts/python/interactive.py +17 -26
- machineconfig/scripts/python/{machineconfig.py → mcfg_entry.py} +4 -5
- machineconfig/scripts/python/msearch.py +57 -6
- machineconfig/scripts/python/sessions.py +100 -31
- machineconfig/scripts/python/terminal.py +26 -17
- machineconfig/scripts/python/utils.py +17 -15
- machineconfig/scripts/windows/wrap_mcfg.ps1 +6 -3
- machineconfig/settings/lf/windows/lfcd.ps1 +1 -1
- machineconfig/settings/linters/.ruff.toml +1 -1
- machineconfig/settings/shells/bash/init.sh +29 -2
- machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +1 -1
- machineconfig/settings/shells/nushell/config.nu +2 -2
- machineconfig/settings/shells/nushell/env.nu +45 -6
- machineconfig/settings/shells/nushell/init.nu +282 -95
- machineconfig/settings/shells/pwsh/init.ps1 +1 -0
- machineconfig/settings/shells/wezterm/wezterm.lua +2 -0
- machineconfig/settings/shells/zsh/init.sh +1 -8
- 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/wt/__init__.py +0 -0
- machineconfig/settings/yazi/init.lua +49 -24
- machineconfig/settings/yazi/keymap_linux.toml +19 -4
- machineconfig/settings/yazi/keymap_windows.toml +0 -1
- machineconfig/settings/yazi/shell/yazi_cd.ps1 +29 -5
- machineconfig/settings/yazi/theme.toml +4 -0
- machineconfig/settings/yazi/yazi_linux.toml +84 -0
- machineconfig/settings/yazi/yazi_windows.toml +58 -0
- machineconfig/settings/zellij/layouts/st.kdl +39 -8
- machineconfig/setup_linux/__init__.py +1 -2
- machineconfig/setup_linux/apps_desktop.sh +8 -27
- machineconfig/setup_linux/web_shortcuts/interactive.sh +12 -10
- machineconfig/setup_linux/web_shortcuts/live_from_github.sh +31 -0
- machineconfig/setup_mac/__init__.py +2 -3
- machineconfig/setup_windows/__init__.py +3 -5
- machineconfig/setup_windows/ssh/openssh-server.ps1 +1 -1
- machineconfig/setup_windows/uv.ps1 +8 -1
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +12 -10
- machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +30 -0
- machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +17 -0
- machineconfig/utils/accessories.py +7 -4
- machineconfig/utils/code.py +39 -11
- machineconfig/utils/files/headers.py +2 -2
- machineconfig/utils/installer_utils/github_release_bulk.py +156 -119
- machineconfig/utils/installer_utils/install_from_url.py +183 -0
- machineconfig/utils/installer_utils/installer_class.py +43 -100
- machineconfig/utils/installer_utils/installer_cli.py +175 -0
- machineconfig/utils/installer_utils/installer_helper.py +129 -0
- machineconfig/utils/installer_utils/{installer_abc.py → installer_locator_utils.py} +36 -85
- machineconfig/utils/{installer.py → installer_utils/installer_runner.py} +16 -59
- machineconfig/utils/io.py +0 -1
- machineconfig/utils/links.py +2 -2
- machineconfig/utils/meta.py +30 -16
- machineconfig/utils/options.py +42 -24
- machineconfig/utils/options_tv.py +119 -0
- machineconfig/utils/path_extended.py +42 -20
- machineconfig/utils/path_helper.py +75 -22
- machineconfig/utils/procs.py +1 -1
- machineconfig/utils/scheduler.py +20 -53
- machineconfig/utils/schemas/layouts/layout_types.py +1 -1
- machineconfig/utils/ssh.py +159 -418
- machineconfig/utils/ssh_utils/abc.py +5 -0
- machineconfig/utils/ssh_utils/copy_from_here.py +111 -0
- machineconfig/utils/ssh_utils/copy_to_here.py +303 -0
- machineconfig/utils/ssh_utils/utils.py +142 -0
- machineconfig/utils/ssh_utils/wsl.py +210 -0
- machineconfig/utils/terminal.py +1 -0
- machineconfig/utils/upgrade_packages.py +6 -1
- machineconfig/utils/ve.py +12 -4
- machineconfig-8.12.dist-info/METADATA +132 -0
- {machineconfig-7.50.dist-info → machineconfig-8.12.dist-info}/RECORD +265 -215
- {machineconfig-7.50.dist-info → machineconfig-8.12.dist-info}/entry_points.txt +2 -4
- 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/scripts/linux/other/switch_ip +0 -20
- machineconfig/scripts/python/ai/command_runner/prompt.txt +0 -9
- machineconfig/scripts/python/define.py +0 -31
- machineconfig/scripts/python/explore.py +0 -49
- machineconfig/scripts/python/helpers_devops/cli_utils.py +0 -246
- machineconfig/scripts/python/helpers_msearch/scripts_linux/fzfag +0 -17
- machineconfig/scripts/python/helpers_msearch/scripts_linux/fzfrga +0 -21
- machineconfig/scripts/python/helpers_msearch/scripts_linux/skrg +0 -4
- machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfb.ps1 +0 -3
- machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfrga.bat +0 -20
- machineconfig/scripts/python/helpers_repos/count_lines_frontend.py +0 -17
- machineconfig/scripts/python/nw/add_ssh_key.py +0 -148
- machineconfig/scripts/python/nw/wsl_windows_transfer.py +0 -66
- 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 -17
- machineconfig/setup_linux/apps.sh +0 -66
- machineconfig/setup_linux/others/cli_installation.sh +0 -137
- 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_windows/apps.ps1 +0 -62
- machineconfig/setup_windows/others/obs.ps1 +0 -4
- machineconfig/setup_windows/ssh/add_identity.ps1 +0 -11
- machineconfig/utils/installer_utils/installer.py +0 -221
- machineconfig-7.50.dist-info/METADATA +0 -92
- /machineconfig/jobs/installer/linux_scripts/{warp-cli.sh → cloudflare_warp_cli.sh} +0 -0
- /machineconfig/jobs/installer/{custom_dev → 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/{setup_linux/others → jobs/scripts/bash_scripts}/mint_keyboard_shortcuts.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/{nw → ai/utils}/__init__.py +0 -0
- /machineconfig/scripts/python/ai/{vscode_tasks.py → utils/vscode_tasks.py} +0 -0
- /machineconfig/{settings/shells/pwsh/profile.ps1 → scripts/python/helpers_fire_command/f.py} +0 -0
- /machineconfig/{setup_windows/wt_and_pwsh → scripts/python/helpers_network}/__init__.py +0 -0
- /machineconfig/scripts/python/{nw → helpers_network}/mount_nw_drive.py +0 -0
- /machineconfig/scripts/python/{nw → helpers_network}/onetimeshare.py +0 -0
- /machineconfig/scripts/python/{nw → helpers_network}/wifi_conn.py +0 -0
- /machineconfig/{setup_windows/wt_and_pwsh → settings/wt}/set_wt_settings.py +0 -0
- {machineconfig-7.50.dist-info → machineconfig-8.12.dist-info}/WHEEL +0 -0
- {machineconfig-7.50.dist-info → machineconfig-8.12.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
from git import Repo
|
|
6
|
+
from collections import defaultdict
|
|
7
|
+
from datetime import datetime, date
|
|
8
|
+
from typing import Any, Dict, List, Optional, Union
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def count_historical_line_edits(repo_path: str) -> int:
|
|
14
|
+
|
|
15
|
+
repo = Repo(repo_path)
|
|
16
|
+
last_commit = next(repo.iter_commits())
|
|
17
|
+
total_lines, total_files = count_python_lines(last_commit)
|
|
18
|
+
print(f"Total lines of Python code in latest commit ({last_commit.hexsha[:8]}): {total_lines} across {total_files} files")
|
|
19
|
+
|
|
20
|
+
gitcs_viz(repo_path=repo_path, pull_full_history=True)
|
|
21
|
+
|
|
22
|
+
file_line_counts: "Dict[str, int]" = defaultdict(int)
|
|
23
|
+
total_commits: int = sum(1 for _ in repo.iter_commits())
|
|
24
|
+
print(f"Total commits to process: {total_commits}")
|
|
25
|
+
for i, commit in enumerate(repo.iter_commits(), 1):
|
|
26
|
+
if i % 100 == 0 or i == total_commits:
|
|
27
|
+
print(f"Processing commit {i}/{total_commits} ({i / total_commits:.1%})")
|
|
28
|
+
try:
|
|
29
|
+
# Handle initial commits that have no parents
|
|
30
|
+
if not commit.parents:
|
|
31
|
+
# For initial commit, count all lines in Python files
|
|
32
|
+
for file in commit.stats.files:
|
|
33
|
+
if str(file).endswith(".py"):
|
|
34
|
+
file_line_counts[str(file)] += commit.stats.files[file]["insertions"]
|
|
35
|
+
else:
|
|
36
|
+
# For commits with parents, use stats
|
|
37
|
+
for file in commit.stats.files:
|
|
38
|
+
if str(file).endswith(".py"):
|
|
39
|
+
file_line_counts[str(file)] += commit.stats.files[file]["insertions"]
|
|
40
|
+
except Exception:
|
|
41
|
+
# If stats fail (e.g., corrupted parent), skip this commit
|
|
42
|
+
print(f"Warning: Could not get stats for commit {commit.hexsha[:8]}, skipping")
|
|
43
|
+
continue
|
|
44
|
+
|
|
45
|
+
print(f"\nProcessed files: {len(file_line_counts)}")
|
|
46
|
+
res = sum(file_line_counts.values())
|
|
47
|
+
print(f"Total historical lines of Python code: {res}")
|
|
48
|
+
return res
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def count_lines_changed_in_commit(commit: "Any") -> int:
|
|
54
|
+
_total_lines = 0
|
|
55
|
+
for _file in commit.stats.files:
|
|
56
|
+
if str(_file).endswith(".py"):
|
|
57
|
+
_blob = commit.tree / _file
|
|
58
|
+
_total_lines += len(_blob.data_stream.read().decode("utf-8").splitlines())
|
|
59
|
+
return _total_lines
|
|
60
|
+
def count_python_lines(commit: "Any") -> tuple[int, int]:
|
|
61
|
+
"""Count total lines in Python files for a specific commit"""
|
|
62
|
+
total_lines = 0
|
|
63
|
+
total_files = 0
|
|
64
|
+
try:
|
|
65
|
+
for blob in commit.tree.traverse():
|
|
66
|
+
if blob.path.endswith(".py"):
|
|
67
|
+
try:
|
|
68
|
+
content = blob.data_stream.read().decode("utf-8")
|
|
69
|
+
total_lines += len(content.splitlines())
|
|
70
|
+
total_files += 1
|
|
71
|
+
except Exception as _e:
|
|
72
|
+
continue
|
|
73
|
+
except Exception as e:
|
|
74
|
+
print(f"Error traversing commit {commit.hexsha[:8]}: {e}")
|
|
75
|
+
pass
|
|
76
|
+
return total_lines, total_files
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def get_default_branch(repo: Repo) -> str:
|
|
80
|
+
"""Get the default branch name of the repository"""
|
|
81
|
+
try:
|
|
82
|
+
_ = repo.refs["main"]
|
|
83
|
+
return "main" # First try 'main'
|
|
84
|
+
except IndexError:
|
|
85
|
+
try:
|
|
86
|
+
_ = repo.refs["master"]
|
|
87
|
+
return "master" # Then try 'master'
|
|
88
|
+
except IndexError:
|
|
89
|
+
return repo.head.reference.name # If neither exists, get the branch the HEAD is pointing to
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def gitcs_viz(repo_path: Union[str, Path], email: Optional[str] = None, pull_full_history: bool = False) -> None:
|
|
94
|
+
"""Invoke the gitcs CLI across 6-month windows covering the repo history.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
repo_path: Path to the git repository
|
|
98
|
+
email: Optional email filter for gitcs
|
|
99
|
+
pull_full_history: If True, unshallow the repo to fetch full history (useful for shallow clones)
|
|
100
|
+
"""
|
|
101
|
+
from machineconfig.utils.installer_utils.installer_cli import install_if_missing
|
|
102
|
+
install_if_missing("gitcs")
|
|
103
|
+
|
|
104
|
+
repo_path = Path(repo_path).expanduser().resolve()
|
|
105
|
+
repo = Repo(repo_path)
|
|
106
|
+
|
|
107
|
+
# Check if repo is shallow and optionally unshallow it
|
|
108
|
+
if pull_full_history:
|
|
109
|
+
shallow_file = Path(repo.git_dir) / "shallow"
|
|
110
|
+
if shallow_file.exists():
|
|
111
|
+
print("🔄 Detected shallow clone. Fetching full history...")
|
|
112
|
+
try:
|
|
113
|
+
repo.git.fetch("--unshallow")
|
|
114
|
+
print("✅ Successfully fetched full history")
|
|
115
|
+
except Exception as e:
|
|
116
|
+
print(f"⚠️ Failed to unshallow repository: {e}")
|
|
117
|
+
print("Continuing with available history...")
|
|
118
|
+
else:
|
|
119
|
+
print("ℹ️ Repository already has full history")
|
|
120
|
+
|
|
121
|
+
branch_name = get_default_branch(repo)
|
|
122
|
+
commits: "List[Any]" = list(repo.iter_commits(branch_name))
|
|
123
|
+
if not commits:
|
|
124
|
+
print("⚠️ No commits found; skipping gitcs visualization.")
|
|
125
|
+
return
|
|
126
|
+
|
|
127
|
+
from datetime import timezone
|
|
128
|
+
|
|
129
|
+
commit_dates = [datetime.fromtimestamp(commit.committed_date, tz=timezone.utc).date() for commit in commits]
|
|
130
|
+
min_year = min(commit_dates).year
|
|
131
|
+
max_year = max(commit_dates).year
|
|
132
|
+
|
|
133
|
+
print(f"📆 gitcs windows: {min_year}-01-01 → {max_year}-12-31 (fixed half-year slices)")
|
|
134
|
+
|
|
135
|
+
chunk_idx = 1
|
|
136
|
+
for year in range(min_year, max_year + 1):
|
|
137
|
+
windows = [(date(year, 1, 1), date(year, 6, 30)), (date(year, 7, 1), date(year, 12, 31))]
|
|
138
|
+
for chunk_start, chunk_end in windows:
|
|
139
|
+
cmd = ["gitcs", "--since", chunk_start.isoformat(), "--until", chunk_end.isoformat()]
|
|
140
|
+
if email:
|
|
141
|
+
cmd.extend(["--email", email])
|
|
142
|
+
|
|
143
|
+
print(f"\n===== gitcs chunk {chunk_idx}: {chunk_start.isoformat()} → {chunk_end.isoformat()} =====")
|
|
144
|
+
try:
|
|
145
|
+
completed = subprocess.run(cmd, cwd=str(repo_path), capture_output=True, text=True, input=f"{repo_path}\n")
|
|
146
|
+
except FileNotFoundError:
|
|
147
|
+
print("❌ gitcs CLI is not available on PATH; aborting visualization.")
|
|
148
|
+
return
|
|
149
|
+
|
|
150
|
+
if completed.stdout.strip():
|
|
151
|
+
print(completed.stdout.strip())
|
|
152
|
+
if completed.stderr.strip():
|
|
153
|
+
print(completed.stderr.strip())
|
|
154
|
+
if completed.returncode != 0:
|
|
155
|
+
print(f"⚠️ gitcs exited with code {completed.returncode} for this range.")
|
|
156
|
+
|
|
157
|
+
chunk_idx += 1
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
@@ -1,189 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
from typing import TYPE_CHECKING, Annotated
|
|
3
1
|
from git import Repo
|
|
4
|
-
from
|
|
2
|
+
from machineconfig.scripts.python.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
|
-
)
|
|
138
|
-
|
|
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
|
-
|
|
146
|
-
# Update layout with dark theme and customizations
|
|
147
|
-
fig.update_layout(
|
|
148
|
-
title={"text": "✨ Python Code Base Size Over Time ✨", "y": 0.95, "x": 0.5, "xanchor": "center", "yanchor": "top", "font": {"size": 24, "color": "white"}},
|
|
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)
|
|
169
|
-
|
|
170
|
-
html_path = plot_dir.joinpath("code_size_evolution.html")
|
|
171
|
-
png_path = plot_dir.joinpath("code_size_evolution.png")
|
|
172
|
-
|
|
173
|
-
fig.write_html(html_path, include_plotlyjs="cdn")
|
|
174
|
-
fig.write_image(png_path, width=1200, height=700, scale=2)
|
|
175
|
-
|
|
176
|
-
print(f"🖼️ Interactive plot saved as {html_path}")
|
|
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")
|
|
6
|
+
from typing import Any, Dict, List, Union, Optional
|
|
184
7
|
|
|
185
8
|
|
|
186
|
-
def
|
|
9
|
+
def print_python_files_by_size_impl(repo_path: str) -> "Union[pl.DataFrame, Exception]":
|
|
187
10
|
import polars as pl
|
|
188
11
|
import plotly.graph_objects as go
|
|
189
12
|
import plotly.express as px
|
|
@@ -227,13 +50,25 @@ def _print_python_files_by_size_impl(repo_path: str) -> "Union[pl.DataFrame, Exc
|
|
|
227
50
|
df = df.sort("lines", descending=True)
|
|
228
51
|
df = df.filter(pl.col("lines") > 0) # Filter out empty files
|
|
229
52
|
|
|
53
|
+
from rich.console import Console
|
|
54
|
+
from rich.table import Table
|
|
55
|
+
|
|
230
56
|
# Add total count
|
|
231
57
|
total_lines = int(df["lines"].sum())
|
|
232
58
|
file_count: int = len(df)
|
|
233
|
-
|
|
59
|
+
console = Console()
|
|
234
60
|
# Print the DataFrame
|
|
235
|
-
print("\n📊 Python Files Line Count (sorted max to min):")
|
|
236
|
-
|
|
61
|
+
console.print("\n📊 Python Files Line Count (sorted max to min):")
|
|
62
|
+
|
|
63
|
+
table = Table(show_header=True, header_style="bold cyan")
|
|
64
|
+
table.add_column("#", justify="right")
|
|
65
|
+
table.add_column("File", overflow="fold")
|
|
66
|
+
table.add_column("Lines", justify="right")
|
|
67
|
+
|
|
68
|
+
for idx, row in enumerate(df.iter_rows(named=True), 1):
|
|
69
|
+
table.add_row(str(idx), row["filename"], f"{row['lines']:,}")
|
|
70
|
+
|
|
71
|
+
console.print(table)
|
|
237
72
|
print(f"\n📁 Total Python files: {file_count}")
|
|
238
73
|
print(f"📝 Total lines of Python code: {total_lines:,}")
|
|
239
74
|
|
|
@@ -335,14 +170,100 @@ def _print_python_files_by_size_impl(repo_path: str) -> "Union[pl.DataFrame, Exc
|
|
|
335
170
|
return Exception(f"❌ Error analyzing repository: {str(e)}")
|
|
336
171
|
|
|
337
172
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
173
|
+
def analyze_over_time(repo_path: str):
|
|
174
|
+
"""Analyze a git repository to track Python code size over time with visualization."""
|
|
175
|
+
repo: Repo = Repo(repo_path)
|
|
176
|
+
branch_name: str = get_default_branch(repo)
|
|
177
|
+
print(f"🔍 Using branch: {branch_name}")
|
|
178
|
+
commit_data: "List[Dict[str, Any]]" = []
|
|
179
|
+
print("⏳ Analyzing commits...")
|
|
180
|
+
try:
|
|
181
|
+
commits = list(repo.iter_commits(branch_name))
|
|
182
|
+
from datetime import timezone
|
|
183
|
+
from rich.progress import track
|
|
184
|
+
for commit in track(commits, description="Processing commits..."):
|
|
185
|
+
commit_data.append({"hash": commit.hexsha, "dtmExit": datetime.fromtimestamp(commit.committed_date, tz=timezone.utc), "lines": count_python_lines(commit)})
|
|
186
|
+
except Exception as e:
|
|
187
|
+
print(f"❌ Error analyzing commits: {str(e)}")
|
|
344
188
|
return
|
|
345
189
|
|
|
190
|
+
import polars as pl
|
|
191
|
+
import plotly.graph_objects as go
|
|
192
|
+
|
|
193
|
+
df = pl.DataFrame(commit_data)
|
|
194
|
+
df = df.sort("dtmExit")
|
|
195
|
+
# Create interactive plotly figure with dark theme and all bells and whistles
|
|
196
|
+
fig = go.Figure()
|
|
197
|
+
# Add line chart with gradient fill and sparkle effect
|
|
198
|
+
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>"))
|
|
199
|
+
# Add markers for significant points (min, max, last)
|
|
200
|
+
min_idx = df["lines"].arg_min()
|
|
201
|
+
max_idx = df["lines"].arg_max()
|
|
202
|
+
min_point = df.slice(min_idx, 1).to_dicts()[0] if min_idx is not None else {}
|
|
203
|
+
max_point = df.slice(max_idx, 1).to_dicts()[0] if max_idx is not None else {}
|
|
204
|
+
last_point = df.slice(-1, 1).to_dicts()[0]
|
|
205
|
+
|
|
206
|
+
# Add markers for significant points
|
|
207
|
+
fig.add_trace(
|
|
208
|
+
go.Scatter(
|
|
209
|
+
x=[min_point["dtmExit"], max_point["dtmExit"], last_point["dtmExit"]],
|
|
210
|
+
y=[min_point["lines"], max_point["lines"], last_point["lines"]],
|
|
211
|
+
mode="markers",
|
|
212
|
+
marker={"size": [10, 14, 12], "color": ["#ff4f4f", "#4fff4f", "#4f4fff"], "line": {"width": 2, "color": "white"}, "symbol": ["circle", "star", "diamond"]},
|
|
213
|
+
name="Key Points",
|
|
214
|
+
hovertemplate="<b>%{text}</b><br>Date: %{x}<br>Lines: %{y:,}<extra></extra>",
|
|
215
|
+
text=[f"🔽 Min: {min_point['lines']:,} lines", f"🔼 Max: {max_point['lines']:,} lines", f"📊 Current: {last_point['lines']:,} lines"],
|
|
216
|
+
)
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
# Add annotation only for current point
|
|
220
|
+
# annotations = [
|
|
221
|
+
# {"x": last_point['date'], "y": last_point['lines'], "text": f"📊 Current: {last_point['lines']:,} lines", "showarrow": True, "arrowhead": 2, "arrowsize": 1,
|
|
222
|
+
# "arrowwidth": 2, "arrowcolor": "#ffffff", "font": {"size": 14, "color": "#ffffff"}, "bgcolor": "#00b4ff", "bordercolor": "#ffffff",
|
|
223
|
+
# "borderwidth": 1, "borderpad": 4, "ax": 40, "ay": -40}
|
|
224
|
+
# ]
|
|
346
225
|
|
|
347
|
-
|
|
348
|
-
|
|
226
|
+
# Update layout with dark theme and customizations
|
|
227
|
+
fig.update_layout(
|
|
228
|
+
title={"text": "✨ Python Code Base Size Over Time ✨", "y": 0.95, "x": 0.5, "xanchor": "center", "yanchor": "top", "font": {"size": 24, "color": "white"}},
|
|
229
|
+
xaxis_title="Date 📅",
|
|
230
|
+
yaxis_title="Lines of Code 📝",
|
|
231
|
+
hovermode="closest",
|
|
232
|
+
template="plotly_dark",
|
|
233
|
+
plot_bgcolor="rgba(25, 25, 35, 1)",
|
|
234
|
+
paper_bgcolor="rgba(15, 15, 25, 1)",
|
|
235
|
+
font={"family": "Arial, sans-serif", "size": 14, "color": "white"}, # annotations=annotations,
|
|
236
|
+
autosize=True,
|
|
237
|
+
height=700,
|
|
238
|
+
margin={"l": 80, "r": 80, "t": 100, "b": 80},
|
|
239
|
+
xaxis={"showgrid": True, "gridcolor": "rgba(80, 80, 100, 0.2)", "showline": True, "linecolor": "rgba(200, 200, 255, 0.2)", "tickfont": {"size": 12}},
|
|
240
|
+
yaxis={"showgrid": True, "gridcolor": "rgba(80, 80, 100, 0.2)", "showline": True, "linecolor": "rgba(200, 200, 255, 0.2)", "tickformat": ",", "tickfont": {"size": 12}},
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
# Add range slider for date selection
|
|
244
|
+
fig.update_xaxes(rangeslider_visible=True, rangeslider_thickness=0.05)
|
|
245
|
+
|
|
246
|
+
# Save as interactive HTML and static image
|
|
247
|
+
plot_dir = Path.home().joinpath("tmp_results", "tmp_images", Path(repo_path).name)
|
|
248
|
+
plot_dir.mkdir(parents=True, exist_ok=True)
|
|
249
|
+
|
|
250
|
+
html_path = plot_dir.joinpath("code_size_evolution.html")
|
|
251
|
+
png_path = plot_dir.joinpath("code_size_evolution.png")
|
|
252
|
+
|
|
253
|
+
try:
|
|
254
|
+
fig.write_html(html_path, include_plotlyjs="cdn")
|
|
255
|
+
except Exception as e:
|
|
256
|
+
print(f"❌ Error saving HTML plot: {str(e)}")
|
|
257
|
+
try:
|
|
258
|
+
fig.write_image(png_path, width=1200, height=700, scale=2)
|
|
259
|
+
except Exception as e:
|
|
260
|
+
print(f"❌ Error saving PNG plot: {str(e)}")
|
|
261
|
+
|
|
262
|
+
print(f"🖼️ Interactive plot saved as {html_path}")
|
|
263
|
+
print(f"🖼️ Static image saved as {png_path}")
|
|
264
|
+
# Print statistics
|
|
265
|
+
print("\n📊 Repository Statistics:")
|
|
266
|
+
print(f"📚 Total commits analyzed: {len(df)}")
|
|
267
|
+
print(f"🔙 Initial line count: {df['lines'][-1]:,}")
|
|
268
|
+
print(f"🔜 Final line count: {df['lines'][0]:,}")
|
|
269
|
+
print(f"📈 Net change: {df['lines'][0] - df['lines'][-1]:,} lines")
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
3
|
from typing import Optional, Annotated
|
|
4
|
-
from pathlib import Path
|
|
5
4
|
import typer
|
|
6
5
|
|
|
7
6
|
|
|
@@ -10,23 +9,23 @@ def create_from_function(
|
|
|
10
9
|
path: Annotated[str, typer.Option(..., "--path", "-p", help="Path to a Python or Shell script file or a directory containing such files")] = ".",
|
|
11
10
|
function: Annotated[Optional[str], typer.Option(..., "--function", "-f", help="Function to run from the Python file. If not provided, you will be prompted to choose.")] = None,
|
|
12
11
|
):
|
|
13
|
-
from machineconfig.utils.ve import
|
|
12
|
+
from machineconfig.utils.ve import get_ve_path_and_ipython_profile
|
|
14
13
|
from machineconfig.utils.options import choose_from_options
|
|
15
14
|
from machineconfig.utils.path_helper import match_file_name, sanitize_path
|
|
16
|
-
from machineconfig.utils.path_extended import PathExtended
|
|
17
15
|
from machineconfig.utils.accessories import get_repo_root
|
|
16
|
+
from pathlib import Path
|
|
18
17
|
|
|
19
18
|
path_obj = sanitize_path(path)
|
|
20
19
|
if not path_obj.exists():
|
|
21
20
|
suffixes = {".py"}
|
|
22
|
-
choice_file = match_file_name(sub_string=path, search_root=
|
|
21
|
+
choice_file = match_file_name(sub_string=path, search_root=Path.cwd(), suffixes=suffixes)
|
|
23
22
|
elif path_obj.is_dir():
|
|
24
|
-
from machineconfig.
|
|
23
|
+
from machineconfig.utils.path_helper import search_for_files_of_interest
|
|
25
24
|
print(f"🔍 Searching recursively for Python, PowerShell and Shell scripts in directory `{path_obj}`")
|
|
26
|
-
files = search_for_files_of_interest(path_obj)
|
|
25
|
+
files = search_for_files_of_interest(path_obj, suffixes={".py", ".sh", ".ps1"})
|
|
27
26
|
print(f"🔍 Got #{len(files)} results.")
|
|
28
|
-
choice_file = choose_from_options(multi=False, options=files,
|
|
29
|
-
choice_file =
|
|
27
|
+
choice_file = choose_from_options(multi=False, options=files, tv=True, msg="Choose one option")
|
|
28
|
+
choice_file = Path(choice_file)
|
|
30
29
|
else:
|
|
31
30
|
choice_file = path_obj
|
|
32
31
|
|
|
@@ -36,10 +35,13 @@ def create_from_function(
|
|
|
36
35
|
ve_root_from_file, ipy_profile = get_ve_path_and_ipython_profile(choice_file)
|
|
37
36
|
if ipy_profile is None:
|
|
38
37
|
ipy_profile = "default"
|
|
39
|
-
if ve_root_from_file is None:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
# if ve_root_from_file is None:
|
|
39
|
+
# raise ValueError(f"Could not determine virtual environment for file {choice_file}. Please ensure it is within a recognized project structure.")
|
|
40
|
+
# _activate_ve_line = get_ve_activate_line(ve_root=ve_root_from_file)
|
|
41
|
+
if ve_root_from_file is not None:
|
|
42
|
+
start_dir = Path(ve_root_from_file).parent
|
|
43
|
+
else:
|
|
44
|
+
start_dir = Path.cwd()
|
|
43
45
|
|
|
44
46
|
# ========================= choosing function to run
|
|
45
47
|
if function is None or function.strip() == "":
|
|
@@ -52,7 +54,11 @@ def create_from_function(
|
|
|
52
54
|
from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
|
|
53
55
|
layout: LayoutConfig = {"layoutName": "fireNprocess", "layoutTabs": []}
|
|
54
56
|
for an_arg in range(num_process):
|
|
55
|
-
layout["layoutTabs"].append({
|
|
57
|
+
layout["layoutTabs"].append({
|
|
58
|
+
"tabName": f"tab{an_arg}",
|
|
59
|
+
"startDir": str(start_dir),
|
|
60
|
+
"command": f"uv run python -m fire {choice_file} {choice_function} --idx={an_arg} --idx_max={num_process}"
|
|
61
|
+
})
|
|
56
62
|
print(layout)
|
|
57
63
|
run_zellij_layout(layout_config=layout)
|
|
58
64
|
|