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
|
@@ -7,39 +7,20 @@ fire
|
|
|
7
7
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
from machineconfig.utils.ve import get_ve_path_and_ipython_profile
|
|
11
|
-
from machineconfig.utils.options import choose_from_options
|
|
12
|
-
from machineconfig.utils.path_helper import match_file_name, sanitize_path
|
|
13
|
-
from machineconfig.utils.path_extended import PathExtended
|
|
14
|
-
from machineconfig.utils.accessories import get_repo_root, randstr
|
|
15
|
-
from machineconfig.scripts.python.helpers_fire_command.fire_jobs_args_helper import FireJobArgs, extract_kwargs, parse_fire_args_from_context
|
|
16
|
-
|
|
17
|
-
import platform
|
|
18
10
|
from typing import Optional, Annotated
|
|
19
|
-
from pathlib import Path
|
|
20
11
|
import typer
|
|
21
12
|
|
|
22
13
|
|
|
23
|
-
def route(args: FireJobArgs, fire_args: str = "") -> None:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
from machineconfig.scripts.python.helpers_fire_command.file_wrangler import search_for_files_of_interest
|
|
30
|
-
print(f"🔍 Searching recursively for Python, PowerShell and Shell scripts in directory `{path_obj}`")
|
|
31
|
-
files = search_for_files_of_interest(path_obj)
|
|
32
|
-
print(f"🔍 Got #{len(files)} results.")
|
|
33
|
-
choice_file = choose_from_options(multi=False, options=files, fzf=True, msg="Choose one option")
|
|
34
|
-
choice_file = PathExtended(choice_file)
|
|
35
|
-
else:
|
|
36
|
-
choice_file = path_obj
|
|
37
|
-
|
|
38
|
-
repo_root = get_repo_root(Path(choice_file))
|
|
14
|
+
def route(args: "FireJobArgs", fire_args: str = "") -> None:
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from machineconfig.utils.path_helper import get_choice_file
|
|
17
|
+
from machineconfig.utils.accessories import get_repo_root, randstr
|
|
18
|
+
choice_file = get_choice_file(args.path, suffixes=None)
|
|
19
|
+
repo_root = get_repo_root(choice_file)
|
|
39
20
|
print(f"💾 Selected file: {choice_file}.\nRepo root: {repo_root}")
|
|
40
21
|
if args.marimo:
|
|
41
22
|
print(f"🧽 Preparing to launch Marimo notebook for `{choice_file}`...")
|
|
42
|
-
tmp_dir =
|
|
23
|
+
tmp_dir = Path.home().joinpath(f"tmp_results/tmp_scripts/marimo/{choice_file.stem}_{randstr()}")
|
|
43
24
|
tmp_dir.mkdir(parents=True, exist_ok=True)
|
|
44
25
|
script = f"""
|
|
45
26
|
cd {tmp_dir}
|
|
@@ -53,7 +34,7 @@ uv run --project {repo_root} --with marimo marimo edit --host 0.0.0.0 marimo_nb.
|
|
|
53
34
|
|
|
54
35
|
# ========================= preparing kwargs_dict
|
|
55
36
|
if choice_file.suffix == ".py":
|
|
56
|
-
|
|
37
|
+
from machineconfig.scripts.python.helpers_fire_command.fire_jobs_args_helper import extract_kwargs
|
|
57
38
|
kwargs_dict = extract_kwargs(args) # This now returns empty dict, but kept for compatibility
|
|
58
39
|
else:
|
|
59
40
|
kwargs_dict = {}
|
|
@@ -62,70 +43,108 @@ uv run --project {repo_root} --with marimo marimo edit --host 0.0.0.0 marimo_nb.
|
|
|
62
43
|
choice_function: Optional[str] = None # Initialize to avoid unbound variable
|
|
63
44
|
if args.choose_function:
|
|
64
45
|
from machineconfig.scripts.python.helpers_fire_command.fire_jobs_route_helper import choose_function_or_lines
|
|
46
|
+
|
|
65
47
|
choice_function, choice_file, kwargs_dict = choose_function_or_lines(choice_file, kwargs_dict)
|
|
66
48
|
else:
|
|
67
49
|
choice_function = args.function
|
|
68
50
|
|
|
69
51
|
if choice_file.suffix == ".py":
|
|
70
|
-
|
|
52
|
+
module_line = "-m" if args.module else ""
|
|
71
53
|
with_project = f"--project {repo_root} " if repo_root is not None else ""
|
|
54
|
+
interactive_line = "-i" if args.interactive else ""
|
|
55
|
+
if args.interactive:
|
|
56
|
+
from machineconfig.utils.ve import get_ve_path_and_ipython_profile
|
|
57
|
+
_ve_root_from_file, ipy_profile = get_ve_path_and_ipython_profile(init_path=choice_file)
|
|
58
|
+
if ipy_profile is None:
|
|
59
|
+
ipy_profile = "default"
|
|
60
|
+
ipython_line = f"--no-banner --profile {ipy_profile} "
|
|
61
|
+
else:
|
|
62
|
+
ipython_line = ""
|
|
63
|
+
|
|
72
64
|
if args.streamlit:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
elif args.jupyter:
|
|
65
|
+
from machineconfig.scripts.python.helpers_fire_command.fire_jobs_route_helper import get_command_streamlit
|
|
66
|
+
interpreter_line = get_command_streamlit(choice_file=choice_file, environment=args.environment, repo_root=repo_root)
|
|
67
|
+
elif args.jupyter:
|
|
68
|
+
interpreter_line = "jupyter-lab"
|
|
69
|
+
else:
|
|
70
|
+
interpreter_line = "python" if not args.interactive else "ipython"
|
|
71
|
+
|
|
72
|
+
exe_line = f"uv run {with_project} {interpreter_line} {interactive_line} {module_line} {ipython_line}"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
elif choice_file.suffix == ".ps1" or choice_file.suffix == ".sh":
|
|
76
|
+
exe_line = "."
|
|
77
|
+
elif choice_file.suffix == "":
|
|
78
|
+
exe_line = ""
|
|
79
|
+
else:
|
|
80
|
+
raise NotImplementedError(f"File type {choice_file.suffix} not supported, in the sense that I don't know how to fire it.")
|
|
81
|
+
|
|
82
|
+
if args.module and choice_file.suffix == ".py":
|
|
83
|
+
if repo_root is not None:
|
|
84
|
+
choice_file_adjusted = ".".join(Path(choice_file).relative_to(repo_root).parts).replace(".py", "")
|
|
76
85
|
else:
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
exe = f"uv run {with_project} python "
|
|
84
|
-
elif choice_file.suffix == ".ps1" or choice_file.suffix == ".sh": exe = "."
|
|
85
|
-
elif choice_file.suffix == "": exe = ""
|
|
86
|
-
else: raise NotImplementedError(f"File type {choice_file.suffix} not supported, in the sense that I don't know how to fire it.")
|
|
87
|
-
|
|
88
|
-
if args.module or (args.debug and args.choose_function): # because debugging tools do not support choosing functions and don't interplay with fire module. So the only way to have debugging and choose function options is to import the file as a module into a new script and run the function of interest there and debug the new script.
|
|
86
|
+
choice_file_adjusted = ".".join(Path(choice_file).relative_to(Path.cwd()).parts).replace(".py", "")
|
|
87
|
+
else:
|
|
88
|
+
choice_file_adjusted = str(choice_file)
|
|
89
|
+
|
|
90
|
+
if args.script or (args.debug and args.choose_function):
|
|
91
|
+
# because debugging tools do not support choosing functions and don't interplay with fire module. So the only way to have debugging and choose function options is to import the file as a module into a new script and run the function of interest there and debug the new script.
|
|
89
92
|
assert choice_file.suffix == ".py", f"File must be a python file to be imported as a module. Got {choice_file}"
|
|
90
93
|
from machineconfig.scripts.python.helpers_fire_command.file_wrangler import get_import_module_code, wrap_import_in_try_except
|
|
91
94
|
from machineconfig.utils.meta import lambda_to_python_script
|
|
92
95
|
from machineconfig.utils.code import print_code
|
|
96
|
+
|
|
93
97
|
import_code = get_import_module_code(str(choice_file))
|
|
94
|
-
import_code_robust = lambda_to_python_script(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
+
import_code_robust = lambda_to_python_script(
|
|
99
|
+
lambda: wrap_import_in_try_except(
|
|
100
|
+
import_line=import_code, pyfile=str(choice_file), repo_root=str(repo_root) if repo_root is not None else None
|
|
101
|
+
),
|
|
102
|
+
in_global=True,
|
|
103
|
+
import_module=False,
|
|
104
|
+
)
|
|
105
|
+
# print(f"🧩 Preparing import code for module import:\n{import_code}")
|
|
106
|
+
code_printing = lambda_to_python_script(
|
|
107
|
+
lambda: print_code(code=import_code_robust, lexer="python", desc="import as module code"),
|
|
108
|
+
in_global=True, import_module=False
|
|
109
|
+
)
|
|
110
|
+
print(f"🧩 Preparing import code for module import:\n{import_code}")
|
|
111
|
+
if choice_function is not None:
|
|
112
|
+
calling = f"""res = {choice_function}({("**" + str(kwargs_dict)) if kwargs_dict else ""})"""
|
|
113
|
+
else:
|
|
114
|
+
calling = """# No function selected to call. You can add your code here."""
|
|
98
115
|
choice_file = Path.home().joinpath(f"tmp_results/tmp_scripts/python/{Path(choice_file).parent.name}_{Path(choice_file).stem}_{randstr()}.py")
|
|
99
116
|
choice_file.parent.mkdir(parents=True, exist_ok=True)
|
|
100
117
|
choice_file.write_text(import_code_robust + "\n" + code_printing + "\n" + calling, encoding="utf-8")
|
|
101
118
|
|
|
102
|
-
# ========================= determining basic command structure: putting together exe & choice_file & choice_function & pdb
|
|
103
119
|
if args.debug:
|
|
120
|
+
import platform
|
|
104
121
|
if platform.system() == "Windows":
|
|
105
|
-
command = f"{
|
|
122
|
+
command = f"{exe_line} -m ipdb {choice_file_adjusted} " # pudb is not available on windows machines, use poor man's debugger instead.
|
|
106
123
|
elif platform.system() in ["Linux", "Darwin"]:
|
|
107
|
-
command = f"{
|
|
124
|
+
command = f"{exe_line} -m pudb {choice_file_adjusted} " # TODO: functions not supported yet in debug mode.
|
|
108
125
|
else:
|
|
109
126
|
raise NotImplementedError(f"Platform {platform.system()} not supported.")
|
|
110
127
|
elif args.module:
|
|
111
128
|
# both selected function and kwargs are mentioned in the made up script, therefore no need for fire module.
|
|
112
|
-
command = f"{
|
|
129
|
+
command = f"{exe_line} {choice_file_adjusted} "
|
|
113
130
|
elif choice_function is not None and choice_file.suffix == ".py":
|
|
114
|
-
command = f"{
|
|
131
|
+
command = f"{exe_line} -m fire {choice_file_adjusted} {choice_function} {fire_args}"
|
|
115
132
|
elif args.streamlit:
|
|
116
133
|
# for .streamlit config to work, it needs to be in the current directory.
|
|
117
134
|
if args.holdDirectory:
|
|
118
|
-
command = f"{
|
|
135
|
+
command = f"{exe_line} {choice_file}"
|
|
119
136
|
else:
|
|
120
|
-
command = f"cd {choice_file.parent}\n{
|
|
137
|
+
command = f"cd {choice_file.parent}\n{exe_line} {choice_file.name}\ncd {Path.cwd()}"
|
|
121
138
|
elif args.cmd:
|
|
122
|
-
command = rf""" cd /d {choice_file.parent} & {
|
|
139
|
+
command = rf""" cd /d {choice_file.parent} & {exe_line} {choice_file.name} """
|
|
123
140
|
else:
|
|
124
|
-
if choice_file.suffix == "":
|
|
125
|
-
|
|
126
|
-
|
|
141
|
+
if choice_file.suffix == "":
|
|
142
|
+
command = f"{exe_line} {choice_file} {fire_args}"
|
|
143
|
+
else:
|
|
144
|
+
command = f"{exe_line} {choice_file} "
|
|
127
145
|
|
|
128
|
-
if not args.cmd:
|
|
146
|
+
if not args.cmd:
|
|
147
|
+
pass
|
|
129
148
|
else:
|
|
130
149
|
new_line = "\n"
|
|
131
150
|
command = rf"""start cmd -Argument "/k {command.replace(new_line, " & ")} " """ # this works from powershell
|
|
@@ -134,23 +153,27 @@ uv run --project {repo_root} --with marimo marimo edit --host 0.0.0.0 marimo_nb.
|
|
|
134
153
|
if choice_function is not None:
|
|
135
154
|
command += f"--function {choice_function} "
|
|
136
155
|
|
|
137
|
-
if args.optimized:
|
|
156
|
+
if args.optimized:
|
|
157
|
+
command = command.replace("python ", "python -OO ")
|
|
138
158
|
|
|
139
159
|
from rich.panel import Panel
|
|
140
160
|
from rich.console import Console
|
|
141
161
|
from rich.syntax import Syntax
|
|
162
|
+
|
|
142
163
|
console = Console()
|
|
143
164
|
if args.zellij_tab is not None:
|
|
144
|
-
comman_path__ =
|
|
165
|
+
comman_path__ = Path.home().joinpath(f"tmp_results/tmp_scripts/zellij_commands/{choice_file.stem}_{randstr()}.sh")
|
|
145
166
|
comman_path__.parent.mkdir(parents=True, exist_ok=True)
|
|
146
167
|
comman_path__.write_text(command, encoding="utf-8")
|
|
147
168
|
console.print(Panel(Syntax(command, lexer="shell"), title=f"🔥 fire command @ {comman_path__}: "), style="bold red")
|
|
148
169
|
import subprocess
|
|
170
|
+
|
|
149
171
|
existing_tab_names = subprocess.run(["zellij", "action", "query-tab-names"], capture_output=True, text=True, check=True).stdout.splitlines()
|
|
150
172
|
if args.zellij_tab in existing_tab_names:
|
|
151
173
|
print(f"⚠️ Tab name `{args.zellij_tab}` already exists. Please choose a different name.")
|
|
152
174
|
args.zellij_tab += f"_{randstr(3)}"
|
|
153
175
|
from machineconfig.cluster.sessions_managers.zellij_local import run_command_in_zellij_tab
|
|
176
|
+
|
|
154
177
|
command = run_command_in_zellij_tab(command=str(comman_path__), tab_name=args.zellij_tab, cwd=None)
|
|
155
178
|
if args.watch:
|
|
156
179
|
command = "watchexec --restart --exts py,sh,ps1 " + command
|
|
@@ -158,16 +181,17 @@ uv run --project {repo_root} --with marimo marimo edit --host 0.0.0.0 marimo_nb.
|
|
|
158
181
|
command = f"\ngit -C {choice_file.parent} pull\n" + command
|
|
159
182
|
if args.PathExport:
|
|
160
183
|
from machineconfig.scripts.python.helpers_fire_command.file_wrangler import add_to_path
|
|
184
|
+
|
|
161
185
|
export_line = add_to_path(path_variable="PYTHONPATH", directory=str(repo_root))
|
|
162
186
|
command = export_line + "\n" + command
|
|
163
187
|
if args.loop:
|
|
188
|
+
import platform
|
|
164
189
|
if platform.system() in ["Linux", "Darwin"]:
|
|
165
190
|
command = command + "\nsleep 0.5"
|
|
166
191
|
elif platform.system() == "Windows":
|
|
167
192
|
command = "$ErrorActionPreference = 'SilentlyContinue';\n" + command + "\nStart-Sleep -Seconds 0.5"
|
|
168
193
|
else:
|
|
169
194
|
raise NotImplementedError(f"Platform {platform.system()} not supported.")
|
|
170
|
-
|
|
171
195
|
from machineconfig.utils.code import exit_then_run_shell_script
|
|
172
196
|
exit_then_run_shell_script(script=command, strict=False)
|
|
173
197
|
|
|
@@ -185,23 +209,24 @@ def fire(
|
|
|
185
209
|
jupyter: Annotated[bool, typer.Option("--jupyter", "-j", help="Open in a jupyter notebook")] = False,
|
|
186
210
|
marimo: Annotated[bool, typer.Option("--marimo", "-M", help="Open in a marimo notebook")] = False,
|
|
187
211
|
module: Annotated[bool, typer.Option("--module", "-m", help="Launch the main file")] = False,
|
|
212
|
+
script: Annotated[bool, typer.Option("--script", "-s", help="Launch as a script without fire")] = False,
|
|
188
213
|
optimized: Annotated[bool, typer.Option("--optimized", "-O", help="Run the optimized version of the function")] = False,
|
|
189
214
|
zellij_tab: Annotated[Optional[str], typer.Option("--zellij-tab", "-z", help="Open in a new zellij tab")] = None,
|
|
190
|
-
|
|
191
215
|
submit_to_cloud: Annotated[bool, typer.Option("--submit-to-cloud", "-C", help="Submit to cloud compute")] = False,
|
|
192
216
|
remote: Annotated[bool, typer.Option("--remote", "-r", help="Launch on a remote machine")] = False,
|
|
193
|
-
|
|
194
217
|
streamlit: Annotated[bool, typer.Option("--streamlit", "-S", help="Run as streamlit app")] = False,
|
|
195
218
|
environment: Annotated[str, typer.Option("--environment", "-E", help="Choose ip, localhost, hostname or arbitrary url")] = "",
|
|
196
|
-
holdDirectory: Annotated[
|
|
219
|
+
holdDirectory: Annotated[
|
|
220
|
+
bool, typer.Option("--holdDirectory", "-D", help="Hold current directory and avoid cd'ing to the script directory")
|
|
221
|
+
] = False,
|
|
197
222
|
PathExport: Annotated[bool, typer.Option("--PathExport", "-P", help="Augment the PYTHONPATH with repo root")] = False,
|
|
198
|
-
|
|
199
223
|
git_pull: Annotated[bool, typer.Option("--git-pull", "-g", help="Start by pulling the git repo")] = False,
|
|
200
224
|
watch: Annotated[bool, typer.Option("--watch", "-w", help="Watch the file for changes")] = False,
|
|
201
225
|
) -> None:
|
|
202
226
|
"""Main function to process fire jobs arguments."""
|
|
203
227
|
|
|
204
228
|
# Get Fire arguments from context
|
|
229
|
+
from machineconfig.scripts.python.helpers_fire_command.fire_jobs_args_helper import FireJobArgs, parse_fire_args_from_context
|
|
205
230
|
fire_args = parse_fire_args_from_context(ctx)
|
|
206
231
|
|
|
207
232
|
args = FireJobArgs(
|
|
@@ -218,6 +243,7 @@ def fire(
|
|
|
218
243
|
submit_to_cloud=submit_to_cloud,
|
|
219
244
|
remote=remote,
|
|
220
245
|
module=module,
|
|
246
|
+
script=script,
|
|
221
247
|
streamlit=streamlit,
|
|
222
248
|
environment=environment,
|
|
223
249
|
holdDirectory=holdDirectory,
|
|
@@ -235,12 +261,14 @@ def fire(
|
|
|
235
261
|
except Exception as e:
|
|
236
262
|
# For other exceptions, print clean error message and exit
|
|
237
263
|
import sys
|
|
264
|
+
|
|
238
265
|
print(f"❌ Error: {e}", file=sys.stderr)
|
|
239
266
|
sys.exit(1)
|
|
240
267
|
|
|
241
268
|
|
|
242
269
|
def get_app():
|
|
243
270
|
from typer import Typer
|
|
271
|
+
|
|
244
272
|
app = Typer(add_completion=False)
|
|
245
273
|
app.command(context_settings={"allow_extra_args": True, "allow_interspersed_args": False})(fire)
|
|
246
274
|
return app
|
|
@@ -252,4 +280,4 @@ def main():
|
|
|
252
280
|
|
|
253
281
|
|
|
254
282
|
if __name__ == "__main__":
|
|
255
|
-
|
|
283
|
+
from machineconfig.scripts.python.helpers_fire_command.fire_jobs_args_helper import FireJobArgs
|
|
@@ -6,17 +6,7 @@ Currently, the only way to work around this is to predifine the host in ~/.ssh/c
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import typer
|
|
9
|
-
from
|
|
10
|
-
from rich.console import Console
|
|
11
|
-
from rich.panel import Panel
|
|
12
|
-
|
|
13
|
-
from machineconfig.utils.ssh import SSH
|
|
14
|
-
from machineconfig.utils.path_extended import PathExtended
|
|
15
|
-
from machineconfig.scripts.python.helpers_cloud.helpers2 import ES
|
|
16
|
-
from machineconfig.utils.accessories import pprint
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
console = Console()
|
|
9
|
+
from typing import Annotated
|
|
20
10
|
|
|
21
11
|
|
|
22
12
|
def ftpx(
|
|
@@ -25,7 +15,42 @@ def ftpx(
|
|
|
25
15
|
recursive: Annotated[bool, typer.Option("--recursive", "-r", help="Send recursively.")] = False,
|
|
26
16
|
zipFirst: Annotated[bool, typer.Option("--zipFirst", "-z", help="Zip before sending.")] = False,
|
|
27
17
|
cloud: Annotated[bool, typer.Option("--cloud", "-c", help="Transfer through the cloud.")] = False,
|
|
18
|
+
overwrite_existing: Annotated[bool, typer.Option("--overwrite-existing", "-o", help="Overwrite existing files on remote when sending from local to remote.")] = False,
|
|
28
19
|
) -> None:
|
|
20
|
+
"""File transfer utility though SSH."""
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
if target == "wsl" or source == "wsl":
|
|
23
|
+
from machineconfig.utils.ssh_utils.wsl import copy_when_inside_windows
|
|
24
|
+
if target == "wsl":
|
|
25
|
+
target_obj = Path(source).expanduser().absolute().relative_to(Path.home())
|
|
26
|
+
source_obj = target_obj
|
|
27
|
+
else:
|
|
28
|
+
source_obj = Path(target).expanduser().absolute().relative_to(Path.home())
|
|
29
|
+
target_obj = source_obj
|
|
30
|
+
copy_when_inside_windows(source_obj, target_obj, overwrite_existing)
|
|
31
|
+
return
|
|
32
|
+
elif source == "win" or target == "win":
|
|
33
|
+
if source == "win":
|
|
34
|
+
source_obj = Path(target).expanduser().absolute().relative_to(Path.home())
|
|
35
|
+
target_obj = source_obj
|
|
36
|
+
else:
|
|
37
|
+
target_obj = Path(source).expanduser().absolute().relative_to(Path.home())
|
|
38
|
+
source_obj = target_obj
|
|
39
|
+
from machineconfig.utils.ssh_utils.wsl import copy_when_inside_wsl
|
|
40
|
+
copy_when_inside_wsl(source_obj, target_obj, overwrite_existing)
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
from rich.console import Console
|
|
44
|
+
from rich.panel import Panel
|
|
45
|
+
|
|
46
|
+
from machineconfig.utils.ssh import SSH
|
|
47
|
+
from machineconfig.utils.path_extended import PathExtended
|
|
48
|
+
from machineconfig.scripts.python.helpers_cloud.helpers2 import ES
|
|
49
|
+
from machineconfig.utils.accessories import pprint
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
console = Console()
|
|
53
|
+
|
|
29
54
|
console.print(
|
|
30
55
|
Panel(
|
|
31
56
|
"\n".join(
|
|
@@ -133,7 +158,7 @@ def ftpx(
|
|
|
133
158
|
border_style="cyan",
|
|
134
159
|
)
|
|
135
160
|
)
|
|
136
|
-
ssh.
|
|
161
|
+
ssh.run_shell_cmd_on_remote(command=f"cloud_copy {resolved_source} :^", verbose_output=True, description="Uploading from remote to the cloud.", strict_stderr=False, strict_return_code=False)
|
|
137
162
|
console.print(
|
|
138
163
|
Panel.fit(
|
|
139
164
|
"⬇️ Cloud transfer mode — downloading from cloud to local...",
|
|
@@ -141,12 +166,14 @@ def ftpx(
|
|
|
141
166
|
border_style="cyan",
|
|
142
167
|
)
|
|
143
168
|
)
|
|
144
|
-
ssh.
|
|
169
|
+
ssh.run_shell_cmd_on_local(command=f"cloud_copy :^ {resolved_target}")
|
|
145
170
|
received_file = PathExtended(resolved_target) # type: ignore
|
|
146
171
|
else:
|
|
147
172
|
if source_is_remote:
|
|
148
|
-
|
|
149
|
-
❌ Path Error: Source must be a remote path (machine:path)"""
|
|
173
|
+
if resolved_source is None:
|
|
174
|
+
typer.echo("""❌ Path Error: Source must be a remote path (machine:path)""")
|
|
175
|
+
typer.Exit(code=1)
|
|
176
|
+
return
|
|
150
177
|
target_display = resolved_target or "<auto>"
|
|
151
178
|
console.print(
|
|
152
179
|
Panel(
|
|
@@ -183,7 +210,7 @@ def ftpx(
|
|
|
183
210
|
padding=(1, 2),
|
|
184
211
|
)
|
|
185
212
|
)
|
|
186
|
-
received_file = ssh.copy_from_here(source_path=resolved_source, target_rel2home=resolved_target, compress_with_zip=zipFirst, recursive=recursive, overwrite_existing=
|
|
213
|
+
received_file = ssh.copy_from_here(source_path=resolved_source, target_rel2home=resolved_target, compress_with_zip=zipFirst, recursive=recursive, overwrite_existing=overwrite_existing)
|
|
187
214
|
|
|
188
215
|
if source_is_remote and isinstance(received_file, PathExtended):
|
|
189
216
|
console.print(
|
|
@@ -213,7 +240,7 @@ def ftpx(
|
|
|
213
240
|
def main() -> None:
|
|
214
241
|
"""Entry point function that uses typer to parse arguments and call main."""
|
|
215
242
|
app = typer.Typer()
|
|
216
|
-
app.command(no_args_is_help=True, help="File transfer utility though SSH.")(ftpx)
|
|
243
|
+
app.command(no_args_is_help=True, help=ftpx.__doc__, short_help="File transfer utility though SSH.")(ftpx)
|
|
217
244
|
app()
|
|
218
245
|
|
|
219
246
|
|
|
@@ -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
|