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,23 +7,28 @@ import subprocess
|
|
|
7
7
|
import platform
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
def find_move_delete_windows(downloaded_file_path: PathExtended,
|
|
11
|
-
print("🔍 PROCESSING WINDOWS EXECUTABLE 🔍")
|
|
12
|
-
if exe_name is not None and
|
|
13
|
-
|
|
10
|
+
def find_move_delete_windows(downloaded_file_path: PathExtended, tool_name: Optional[str], delete: bool, rename_to: Optional[str]):
|
|
11
|
+
# print("🔍 PROCESSING WINDOWS EXECUTABLE 🔍")
|
|
12
|
+
# if exe_name is not None and len(exe_name.split("+")) > 1:
|
|
13
|
+
# last_result = None
|
|
14
|
+
# for a_binary in [x.strip() for x in exe_name.split("+") if x.strip() != ""]:
|
|
15
|
+
# last_result = find_move_delete_windows(downloaded_file_path=downloaded_file_path, exe_name=a_binary, delete=delete, rename_to=rename_to)
|
|
16
|
+
# return last_result
|
|
17
|
+
if tool_name is not None and ".exe" in tool_name:
|
|
18
|
+
tool_name = tool_name.replace(".exe", "")
|
|
14
19
|
if downloaded_file_path.is_file():
|
|
15
20
|
exe = downloaded_file_path
|
|
16
21
|
print(f"📄 Found direct executable file: {exe}")
|
|
17
22
|
else:
|
|
18
23
|
print(f"🔎 Searching for executable in: {downloaded_file_path}")
|
|
19
|
-
if
|
|
24
|
+
if tool_name is None:
|
|
20
25
|
exe = downloaded_file_path.search("*.exe", r=True)[0]
|
|
21
26
|
print(f"✅ Found executable: {exe}")
|
|
22
27
|
else:
|
|
23
|
-
tmp = downloaded_file_path.search(f"{
|
|
28
|
+
tmp = downloaded_file_path.search(f"{tool_name}.exe", r=True)
|
|
24
29
|
if len(tmp) == 1:
|
|
25
30
|
exe = tmp[0]
|
|
26
|
-
print(f"✅ Found exact match for {
|
|
31
|
+
print(f"✅ Found exact match for {tool_name}.exe: {exe}")
|
|
27
32
|
else:
|
|
28
33
|
search_res = downloaded_file_path.search("*.exe", r=True)
|
|
29
34
|
if len(search_res) == 0:
|
|
@@ -52,7 +57,13 @@ def find_move_delete_windows(downloaded_file_path: PathExtended, exe_name: Optio
|
|
|
52
57
|
return exe_new_location
|
|
53
58
|
|
|
54
59
|
|
|
55
|
-
def find_move_delete_linux(downloaded: PathExtended, tool_name: str, delete:
|
|
60
|
+
def find_move_delete_linux(downloaded: PathExtended, tool_name: Optional[str], delete: bool, rename_to: Optional[str]):
|
|
61
|
+
# if len(tool_name.split("+")) > 1:
|
|
62
|
+
# last_result = None
|
|
63
|
+
# for a_binary in [x.strip() for x in tool_name.split("+") if x.strip() != ""]:
|
|
64
|
+
# last_result = find_move_delete_linux(downloaded=downloaded, tool_name=a_binary, delete=False, rename_to=rename_to)
|
|
65
|
+
# return last_result
|
|
66
|
+
|
|
56
67
|
print("🔍 PROCESSING LINUX EXECUTABLE 🔍")
|
|
57
68
|
if downloaded.is_file():
|
|
58
69
|
exe = downloaded
|
|
@@ -64,16 +75,24 @@ def find_move_delete_linux(downloaded: PathExtended, tool_name: str, delete: Opt
|
|
|
64
75
|
exe = res[0]
|
|
65
76
|
print(f"✅ Found match for pattern '*{tool_name}*': {exe}")
|
|
66
77
|
else:
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
exe =
|
|
73
|
-
print(f"✅ Found exact match for '{tool_name}': {exe}")
|
|
74
|
-
else:
|
|
75
|
-
exe = max(exe_search_res, key=lambda x: x.size("kb"))
|
|
78
|
+
if tool_name is None: # no tool name provided, get the largest executable
|
|
79
|
+
search_res = downloaded.search("*", folders=False, files=True, r=True)
|
|
80
|
+
if len(search_res) == 0:
|
|
81
|
+
print(f"❌ ERROR: No search results in `{downloaded}`")
|
|
82
|
+
raise IndexError(f"No executable found in {downloaded}")
|
|
83
|
+
exe = max(search_res, key=lambda x: x.size("kb"))
|
|
76
84
|
print(f"✅ Selected largest executable ({exe.size('kb')} KB): {exe}")
|
|
85
|
+
else:
|
|
86
|
+
exe_search_res = downloaded.search(tool_name, folders=False, r=True)
|
|
87
|
+
if len(exe_search_res) == 0:
|
|
88
|
+
print(f"❌ ERROR: No search results for `{tool_name}` in `{downloaded}`")
|
|
89
|
+
raise IndexError(f"No executable found in {downloaded}")
|
|
90
|
+
elif len(exe_search_res) == 1:
|
|
91
|
+
exe = exe_search_res[0]
|
|
92
|
+
print(f"✅ Found exact match for '{tool_name}': {exe}")
|
|
93
|
+
else:
|
|
94
|
+
exe = max(exe_search_res, key=lambda x: x.size("kb"))
|
|
95
|
+
print(f"✅ Selected largest executable ({exe.size('kb')} KB): {exe}")
|
|
77
96
|
|
|
78
97
|
if rename_to and exe.name != rename_to:
|
|
79
98
|
print(f"🏷️ Renaming '{exe.name}' to '{rename_to}'")
|
|
@@ -191,71 +210,3 @@ def check_if_installed_already(exe_name: str, version: Optional[str], use_cache:
|
|
|
191
210
|
return ("⚠️ NotInstalled", "None", version or "unknown")
|
|
192
211
|
|
|
193
212
|
|
|
194
|
-
def parse_apps_installer_linux(txt: str) -> dict[str, tuple[str, str]]:
|
|
195
|
-
"""Parse Linux shell installation scripts into logical chunks.
|
|
196
|
-
|
|
197
|
-
Splits scripts by # --GROUP:<name>:<description> comment signatures into a dictionary
|
|
198
|
-
mapping block names to (description, shell script content) tuples.
|
|
199
|
-
|
|
200
|
-
Returns:
|
|
201
|
-
dict[str, tuple[str, str]]: Dictionary mapping block/section names to (description, installation_script) tuples
|
|
202
|
-
"""
|
|
203
|
-
chunks = txt.split('# --GROUP:')
|
|
204
|
-
res: dict[str, tuple[str, str]] = {}
|
|
205
|
-
|
|
206
|
-
for chunk in chunks[1:]: # Skip first empty chunk before first group
|
|
207
|
-
lines = chunk.split('\n')
|
|
208
|
-
# First line contains the group name and description in format "NAME:DESCRIPTION"
|
|
209
|
-
group_line = lines[0].strip()
|
|
210
|
-
|
|
211
|
-
# Extract group name and description
|
|
212
|
-
if ':' in group_line:
|
|
213
|
-
parts = group_line.split(':', 1) # Split only on first colon
|
|
214
|
-
group_name = parts[0].strip()
|
|
215
|
-
group_description = parts[1].strip() if len(parts) > 1 else ""
|
|
216
|
-
else:
|
|
217
|
-
group_name = group_line
|
|
218
|
-
group_description = ""
|
|
219
|
-
|
|
220
|
-
# Rest is the content
|
|
221
|
-
content = '\n'.join(lines[1:]).strip()
|
|
222
|
-
|
|
223
|
-
if group_name and content:
|
|
224
|
-
res[group_name] = (group_description, content)
|
|
225
|
-
|
|
226
|
-
return res
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
def parse_apps_installer_windows(txt: str) -> dict[str, tuple[str, str]]:
|
|
230
|
-
"""Parse Windows PowerShell installation scripts into logical chunks.
|
|
231
|
-
|
|
232
|
-
Splits scripts by # --GROUP:<name>:<description> comment signatures into a dictionary
|
|
233
|
-
mapping block names to (description, PowerShell script content) tuples.
|
|
234
|
-
|
|
235
|
-
Returns:
|
|
236
|
-
dict[str, tuple[str, str]]: Dictionary mapping block/section names to (description, installation_script) tuples
|
|
237
|
-
"""
|
|
238
|
-
chunks = txt.split('# --GROUP:')
|
|
239
|
-
res: dict[str, tuple[str, str]] = {}
|
|
240
|
-
|
|
241
|
-
for chunk in chunks[1:]: # Skip first chunk before first group
|
|
242
|
-
lines = chunk.split('\n')
|
|
243
|
-
# First line contains the group name and description in format "NAME:DESCRIPTION"
|
|
244
|
-
group_line = lines[0].strip()
|
|
245
|
-
|
|
246
|
-
# Extract group name and description
|
|
247
|
-
if ':' in group_line:
|
|
248
|
-
parts = group_line.split(':', 1) # Split only on first colon
|
|
249
|
-
group_name = parts[0].strip()
|
|
250
|
-
group_description = parts[1].strip() if len(parts) > 1 else ""
|
|
251
|
-
else:
|
|
252
|
-
group_name = group_line
|
|
253
|
-
group_description = ""
|
|
254
|
-
|
|
255
|
-
# Rest is the content
|
|
256
|
-
content = '\n'.join(lines[1:]).strip()
|
|
257
|
-
|
|
258
|
-
if group_name and content:
|
|
259
|
-
res[group_name] = (group_description, content)
|
|
260
|
-
|
|
261
|
-
return res
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""package manager"""
|
|
2
2
|
|
|
3
|
-
from machineconfig.utils.installer_utils.
|
|
3
|
+
from machineconfig.utils.installer_utils.installer_locator_utils import check_if_installed_already
|
|
4
4
|
from machineconfig.utils.installer_utils.installer_class import Installer
|
|
5
5
|
from machineconfig.utils.schemas.installer.installer_types import InstallerData, InstallerDataFiles, get_normalized_arch, get_os_name, OPERATING_SYSTEMS, CPU_ARCHITECTURES
|
|
6
|
-
from machineconfig.jobs.installer.package_groups import
|
|
6
|
+
from machineconfig.jobs.installer.package_groups import PACKAGE_GROUP2NAMES
|
|
7
7
|
from machineconfig.utils.path_extended import PathExtended
|
|
8
8
|
from machineconfig.utils.source_of_truth import INSTALL_VERSION_ROOT, LINUX_INSTALL_PATH
|
|
9
9
|
from machineconfig.utils.io import read_json
|
|
@@ -18,7 +18,7 @@ from joblib import Parallel, delayed
|
|
|
18
18
|
def check_latest():
|
|
19
19
|
console = Console() # Added console initialization
|
|
20
20
|
console.print(Panel("🔍 CHECKING FOR LATEST VERSIONS", title="Status", expand=False)) # Replaced print with Panel
|
|
21
|
-
installers = get_installers(os=get_os_name(), arch=get_normalized_arch(), which_cats=["
|
|
21
|
+
installers = get_installers(os=get_os_name(), arch=get_normalized_arch(), which_cats=["termabc"])
|
|
22
22
|
installers_github = []
|
|
23
23
|
for inst__ in installers:
|
|
24
24
|
app_name = inst__["appName"]
|
|
@@ -91,8 +91,12 @@ def get_installed_cli_apps():
|
|
|
91
91
|
return apps
|
|
92
92
|
|
|
93
93
|
|
|
94
|
-
def get_installers(os: OPERATING_SYSTEMS, arch: CPU_ARCHITECTURES, which_cats: Optional[list[
|
|
95
|
-
|
|
94
|
+
def get_installers(os: OPERATING_SYSTEMS, arch: CPU_ARCHITECTURES, which_cats: Optional[list[str]]) -> list[InstallerData]:
|
|
95
|
+
import machineconfig.jobs.installer as module
|
|
96
|
+
from pathlib import Path
|
|
97
|
+
res_raw: InstallerDataFiles = read_json(Path(module.__file__).parent.joinpath("installer_data.json"))
|
|
98
|
+
res_all: list[InstallerData] = res_raw["installers"]
|
|
99
|
+
|
|
96
100
|
acceptable_apps_names: list[str] | None = None
|
|
97
101
|
if which_cats is not None:
|
|
98
102
|
acceptable_apps_names = []
|
|
@@ -105,40 +109,17 @@ def get_installers(os: OPERATING_SYSTEMS, arch: CPU_ARCHITECTURES, which_cats: O
|
|
|
105
109
|
if acceptable_apps_names is not None:
|
|
106
110
|
if installer_data["appName"] not in acceptable_apps_names:
|
|
107
111
|
continue
|
|
108
|
-
|
|
109
|
-
|
|
112
|
+
try:
|
|
113
|
+
if installer_data["fileNamePattern"][arch][os] is None:
|
|
114
|
+
continue
|
|
115
|
+
except KeyError as ke:
|
|
116
|
+
print(f"❌ ERROR: Missing key in installer data: {ke}")
|
|
117
|
+
print(f"Installer data: {installer_data}")
|
|
118
|
+
raise KeyError(f"Missing key in installer data: {ke}")
|
|
110
119
|
all_installers.append(installer_data)
|
|
111
120
|
return all_installers
|
|
112
121
|
|
|
113
122
|
|
|
114
|
-
def get_all_installer_data_files() -> list[InstallerData]:
|
|
115
|
-
import machineconfig.jobs.installer as module
|
|
116
|
-
from pathlib import Path
|
|
117
|
-
res_raw: InstallerDataFiles = read_json(Path(module.__file__).parent.joinpath("installer_data.json"))
|
|
118
|
-
res_final: list[InstallerData] = res_raw["installers"]
|
|
119
|
-
return res_final
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def dynamically_extract_installers_system_groups_from_scripts():
|
|
123
|
-
res_final: list[InstallerData] = []
|
|
124
|
-
from platform import system
|
|
125
|
-
if system() == "Windows":
|
|
126
|
-
from machineconfig.setup_windows import APPS
|
|
127
|
-
options_system = parse_apps_installer_windows(APPS.read_text(encoding="utf-8"))
|
|
128
|
-
elif system() == "Linux":
|
|
129
|
-
from machineconfig.setup_linux import APPS
|
|
130
|
-
options_system = parse_apps_installer_linux(APPS.read_text(encoding="utf-8"))
|
|
131
|
-
elif system() == "Darwin":
|
|
132
|
-
from machineconfig.setup_mac import APPS
|
|
133
|
-
options_system = parse_apps_installer_linux(APPS.read_text(encoding="utf-8"))
|
|
134
|
-
else:
|
|
135
|
-
raise NotImplementedError(f"❌ System {system()} not supported")
|
|
136
|
-
os_name = get_os_name()
|
|
137
|
-
for group_name, (docs, script) in options_system.items():
|
|
138
|
-
item: InstallerData = {"appName": group_name, "doc": docs, "repoURL": "CMD", "fileNamePattern": {"amd64": {os_name: script}, "arm64": {os_name: script}}}
|
|
139
|
-
res_final.append(item)
|
|
140
|
-
return res_final
|
|
141
|
-
|
|
142
123
|
|
|
143
124
|
def install_bulk(installers_data: list[InstallerData], safe: bool = False, jobs: int = 10, fresh: bool = False):
|
|
144
125
|
print("🚀 BULK INSTALLATION PROCESS 🚀")
|
|
@@ -148,30 +129,6 @@ def install_bulk(installers_data: list[InstallerData], safe: bool = False, jobs:
|
|
|
148
129
|
print("✅ Version cache cleared")
|
|
149
130
|
if safe:
|
|
150
131
|
pass
|
|
151
|
-
# print("⚠️ Safe installation mode activated...")
|
|
152
|
-
# from machineconfig.jobs.python.check_installations import APP_SUMMARY_PATH
|
|
153
|
-
# if platform.system().lower() == "windows":
|
|
154
|
-
# print("🪟 Moving applications to Windows Apps folder...")
|
|
155
|
-
# # PathExtended.get_env().WindowsPaths().WindowsApps)
|
|
156
|
-
# folder = PathExtended.home().joinpath("AppData/Local/Microsoft/WindowsApps")
|
|
157
|
-
# apps_dir.search("*").apply(lambda app: app.move(folder=folder))
|
|
158
|
-
# elif platform.system().lower() in ["linux", "darwin"]:
|
|
159
|
-
# system_name = "Linux" if platform.system().lower() == "linux" else "macOS"
|
|
160
|
-
# print(f"🐧 Moving applications to {system_name} bin folder...")
|
|
161
|
-
# if platform.system().lower() == "linux":
|
|
162
|
-
# install_path = LINUX_INSTALL_PATH
|
|
163
|
-
# else: # Darwin/macOS
|
|
164
|
-
# install_path = "/usr/local/bin"
|
|
165
|
-
# Terminal().run(f"sudo mv {apps_dir.as_posix()}/* {install_path}/").capture().print_if_unsuccessful(desc=f"MOVING executable to {install_path}", strict_err=True, strict_returncode=True)
|
|
166
|
-
# else:
|
|
167
|
-
# error_msg = f"❌ ERROR: System {platform.system()} not supported"
|
|
168
|
-
# print(error_msg)
|
|
169
|
-
# raise NotImplementedError(error_msg)
|
|
170
|
-
|
|
171
|
-
# apps_dir.delete(sure=True)
|
|
172
|
-
# print(f"✅ Safe installation completed\n{'='*80}")
|
|
173
|
-
# return None
|
|
174
|
-
|
|
175
132
|
print(f"🚀 Starting installation of {len(installers_data)} packages...")
|
|
176
133
|
print("📦 INSTALLING FIRST PACKAGE 📦")
|
|
177
134
|
Installer(installers_data[0]).install(version=None)
|
machineconfig/utils/io.py
CHANGED
machineconfig/utils/links.py
CHANGED
|
@@ -164,7 +164,7 @@ def symlink_map(config_file_default_path: PathExtended, self_managed_config_file
|
|
|
164
164
|
else:
|
|
165
165
|
# Files are different, use on_conflict strategy
|
|
166
166
|
import subprocess
|
|
167
|
-
command = f"""delta --side-by-side "{config_file_default_path}" "{self_managed_config_file_path}" """
|
|
167
|
+
command = f"""delta --paging never --side-by-side "{config_file_default_path}" "{self_managed_config_file_path}" """
|
|
168
168
|
try:
|
|
169
169
|
console.print(Panel(f"🆘 CONFLICT DETECTED | Showing diff between {config_file_default_path} and {self_managed_config_file_path}", title="Conflict Detected", expand=False))
|
|
170
170
|
subprocess.run(command, shell=True, check=True)
|
|
@@ -293,7 +293,7 @@ def copy_map(config_file_default_path: PathExtended, self_managed_config_file_pa
|
|
|
293
293
|
else:
|
|
294
294
|
# Files are different, use on_conflict strategy
|
|
295
295
|
import subprocess
|
|
296
|
-
command = f"""delta --side-by-side "{config_file_default_path}" "{self_managed_config_file_path}" """
|
|
296
|
+
command = f"""delta --paging never --side-by-side "{config_file_default_path}" "{self_managed_config_file_path}" """
|
|
297
297
|
try:
|
|
298
298
|
console.print(Panel(f"🆘 CONFLICT DETECTED | Showing diff between {config_file_default_path} and {self_managed_config_file_path}", title="Conflict Detected", expand=False))
|
|
299
299
|
subprocess.run(command, shell=True, check=True)
|
machineconfig/utils/meta.py
CHANGED
|
@@ -29,7 +29,8 @@ except (ImportError, ModuleNotFoundError) as ex:
|
|
|
29
29
|
return txt
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
def lambda_to_python_script(lmb: Callable[[], Any],
|
|
32
|
+
def lambda_to_python_script(lmb: Callable[[], Any],
|
|
33
|
+
in_global: bool, import_module: bool) -> str:
|
|
33
34
|
"""
|
|
34
35
|
caveats: always use keyword arguments in the lambda call for best results.
|
|
35
36
|
return statement not allowed in the wrapped function (otherwise it can be put in the global space)
|
|
@@ -55,6 +56,16 @@ def lambda_to_python_script(lmb: Callable[[], Any], in_global: bool, import_modu
|
|
|
55
56
|
import types as _types
|
|
56
57
|
from pathlib import Path as _Path
|
|
57
58
|
|
|
59
|
+
def _stringify_annotation(annotation: Any) -> Any:
|
|
60
|
+
if annotation is _inspect.Signature.empty or annotation is _inspect.Parameter.empty:
|
|
61
|
+
return annotation
|
|
62
|
+
if isinstance(annotation, str):
|
|
63
|
+
return annotation
|
|
64
|
+
try:
|
|
65
|
+
return _inspect.formatannotation(annotation)
|
|
66
|
+
except Exception:
|
|
67
|
+
return str(annotation)
|
|
68
|
+
|
|
58
69
|
# sanity checks
|
|
59
70
|
if not (callable(lmb) and isinstance(lmb, _types.LambdaType)):
|
|
60
71
|
raise TypeError("Expected a lambda function object")
|
|
@@ -174,16 +185,18 @@ def lambda_to_python_script(lmb: Callable[[], Any], in_global: bool, import_modu
|
|
|
174
185
|
else:
|
|
175
186
|
new_default = param.default
|
|
176
187
|
|
|
177
|
-
|
|
188
|
+
normalized_annotation = _stringify_annotation(param.annotation)
|
|
189
|
+
|
|
178
190
|
if new_default is _inspect.Parameter.empty:
|
|
179
|
-
new_param = _inspect.Parameter(name, param.kind, annotation=
|
|
191
|
+
new_param = _inspect.Parameter(name, param.kind, annotation=normalized_annotation)
|
|
180
192
|
else:
|
|
181
193
|
new_param = _inspect.Parameter(
|
|
182
|
-
name, param.kind, default=new_default, annotation=
|
|
194
|
+
name, param.kind, default=new_default, annotation=normalized_annotation
|
|
183
195
|
)
|
|
184
196
|
new_params.append(new_param)
|
|
185
197
|
|
|
186
|
-
|
|
198
|
+
return_annotation = _stringify_annotation(sig.return_annotation)
|
|
199
|
+
new_sig = _inspect.Signature(parameters=new_params, return_annotation=return_annotation)
|
|
187
200
|
|
|
188
201
|
# If in_global mode, return kwargs as global assignments + dedented body
|
|
189
202
|
if in_global:
|
|
@@ -200,15 +213,11 @@ def lambda_to_python_script(lmb: Callable[[], Any], in_global: bool, import_modu
|
|
|
200
213
|
|
|
201
214
|
# Build type annotation string if available
|
|
202
215
|
if param.annotation is not _inspect.Parameter.empty:
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
type_str = str(param.annotation)
|
|
209
|
-
except Exception:
|
|
210
|
-
type_str = str(param.annotation)
|
|
211
|
-
global_assignments.append(f"{name}: {type_str} = {repr(value)}")
|
|
216
|
+
annotation_literal = _stringify_annotation(param.annotation)
|
|
217
|
+
if isinstance(annotation_literal, str):
|
|
218
|
+
global_assignments.append(f"{name}: {repr(annotation_literal)} = {repr(value)}")
|
|
219
|
+
else:
|
|
220
|
+
global_assignments.append(f"{name} = {repr(value)}")
|
|
212
221
|
else:
|
|
213
222
|
global_assignments.append(f"{name} = {repr(value)}")
|
|
214
223
|
|
|
@@ -233,10 +242,15 @@ def lambda_to_python_script(lmb: Callable[[], Any], in_global: bool, import_modu
|
|
|
233
242
|
|
|
234
243
|
if "Optional" in result_text or "Any" in result_text or "Union" in result_text or "Literal" in result_text:
|
|
235
244
|
result_text = "from typing import Optional, Any, Union, Literal\n\n" + result_text
|
|
236
|
-
|
|
237
245
|
if import_prefix:
|
|
238
246
|
result_text = f"{import_prefix}{result_text}"
|
|
239
247
|
return result_text
|
|
240
248
|
|
|
241
249
|
if __name__ == "__main__":
|
|
242
|
-
|
|
250
|
+
from machineconfig.utils.code import print_code
|
|
251
|
+
import_code_robust = "<import_code_robust>"
|
|
252
|
+
res = lambda_to_python_script(
|
|
253
|
+
lambda: print_code(code=import_code_robust, lexer="python", desc="import as module code"),
|
|
254
|
+
in_global=True, import_module=False
|
|
255
|
+
)
|
|
256
|
+
print(res)
|
machineconfig/utils/options.py
CHANGED
|
@@ -1,36 +1,54 @@
|
|
|
1
|
+
|
|
1
2
|
from pathlib import Path
|
|
2
|
-
from machineconfig.utils.installer_utils.installer_abc import check_tool_exists
|
|
3
3
|
from rich.text import Text
|
|
4
4
|
from rich.panel import Panel
|
|
5
5
|
from rich.console import Console
|
|
6
6
|
import subprocess
|
|
7
7
|
from typing import Optional, Union, Iterable, overload, Literal, cast
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
# def strip_ansi_codes(text: str) -> str:
|
|
11
|
-
# """Remove ANSI color codes from text."""
|
|
12
|
-
# import re
|
|
13
|
-
# return re.sub(r'\x1b\[[0-9;]*[a-zA-Z]', '', text)
|
|
14
|
-
|
|
15
|
-
|
|
16
9
|
@overload
|
|
17
|
-
def choose_from_options[T](
|
|
10
|
+
def choose_from_options[T](options: Iterable[T], msg: str, multi: Literal[False], custom_input: bool = False, header: str = "", tail: str = "", prompt: str = "", default: Optional[T] = None, tv: bool = False) -> T: ...
|
|
18
11
|
@overload
|
|
19
|
-
def choose_from_options[T](
|
|
20
|
-
def choose_from_options[T](
|
|
12
|
+
def choose_from_options[T](options: Iterable[T], msg: str, multi: Literal[True], custom_input: bool = True, header: str = "", tail: str = "", prompt: str = "", default: Optional[T] = None, tv: bool = False, ) -> list[T]: ...
|
|
13
|
+
def choose_from_options[T](options: Iterable[T], msg: str, multi: bool, custom_input: bool = True, header: str = "", tail: str = "", prompt: str = "", default: Optional[T] = None, tv: bool = False, ) -> Union[T, list[T]]:
|
|
21
14
|
# TODO: replace with https://github.com/tmbo/questionary
|
|
22
15
|
# # also see https://github.com/charmbracelet/gum
|
|
23
16
|
options_strings: list[str] = [str(x) for x in options]
|
|
24
17
|
default_string = str(default) if default is not None else None
|
|
25
18
|
console = Console()
|
|
26
|
-
|
|
27
|
-
#
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
#
|
|
19
|
+
from machineconfig.utils.installer_utils.installer_locator_utils import check_tool_exists
|
|
20
|
+
# from machineconfig.utils.installer_utils.installer_cli import check_tool_exists
|
|
21
|
+
# print("ch1")
|
|
22
|
+
if tv and check_tool_exists("tv"):
|
|
23
|
+
# from pyfzf.pyfzf import FzfPrompt
|
|
24
|
+
# fzf_prompt = FzfPrompt()
|
|
25
|
+
# nl = "\n"
|
|
26
|
+
# choice_string_multi: list[str] = fzf_prompt.prompt(choices=options_strings, fzf_options=("--multi" if multi else "") + f' --prompt "{prompt.replace(nl, " ")}" --ansi') # --border-label={msg.replace(nl, ' ')}")
|
|
27
|
+
# print("ch2")
|
|
28
|
+
from machineconfig.utils.accessories import randstr
|
|
29
|
+
options_txt_path = Path.home().joinpath("tmp_results/tmp_files/choices_" + randstr(6) + ".txt")
|
|
30
|
+
options_txt_path.parent.mkdir(parents=True, exist_ok=True)
|
|
31
|
+
options_txt_path.write_text("\n".join(options_strings), encoding="utf-8")
|
|
32
|
+
|
|
33
|
+
# Run `tv` interactively so the user can make selections. We redirect tv's
|
|
34
|
+
# stdout to a temporary output file so we can read the chosen lines after
|
|
35
|
+
# the interactive session completes. Do not capture_output or redirect
|
|
36
|
+
# stdin/stderr here so `tv` stays attached to the terminal.
|
|
37
|
+
tv_out_path = options_txt_path.with_name(options_txt_path.stem + "_out.txt")
|
|
38
|
+
tv_cmd = f"""cat {options_txt_path} | tv --ansi true --source-output "{{strip_ansi}}" > {tv_out_path}"""
|
|
39
|
+
res = subprocess.run(tv_cmd, shell=True)
|
|
40
|
+
|
|
41
|
+
# If tv returned a non-zero code and there is no output file, treat it as an error.
|
|
42
|
+
if res.returncode != 0 and not tv_out_path.exists():
|
|
43
|
+
raise RuntimeError(f"Got error running tv command: {tv_cmd}\nreturncode: {res.returncode}")
|
|
44
|
+
|
|
45
|
+
# Read selections (if any) from the output file created by tv.
|
|
46
|
+
out_text = tv_out_path.read_text(encoding="utf-8") if tv_out_path.exists() else ""
|
|
47
|
+
choice_string_multi = [x for x in out_text.splitlines() if x.strip() != ""]
|
|
48
|
+
|
|
49
|
+
# Cleanup temporary files
|
|
50
|
+
options_txt_path.unlink(missing_ok=True)
|
|
51
|
+
tv_out_path.unlink(missing_ok=True)
|
|
34
52
|
if not multi:
|
|
35
53
|
try:
|
|
36
54
|
choice_one_string = choice_string_multi[0]
|
|
@@ -65,7 +83,7 @@ def choose_from_options[T](msg: str, options: Iterable[T], multi: bool, custom_i
|
|
|
65
83
|
if choice_string == "":
|
|
66
84
|
if default_string is None:
|
|
67
85
|
console.print(Panel("🧨 Default option not available!", title="Error", expand=False))
|
|
68
|
-
return choose_from_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default,
|
|
86
|
+
return choose_from_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default, tv=tv, multi=multi, custom_input=custom_input)
|
|
69
87
|
choice_idx = options_strings.index(default_string)
|
|
70
88
|
assert default is not None, "🧨 Default option not available!"
|
|
71
89
|
choice_one: T = default
|
|
@@ -83,7 +101,7 @@ def choose_from_options[T](msg: str, options: Iterable[T], multi: bool, custom_i
|
|
|
83
101
|
_ = ie
|
|
84
102
|
# raise ValueError(f"Unknown choice. {choice_string}") from ie
|
|
85
103
|
console.print(Panel(f"❓ Unknown choice: '{choice_string}'", title="Error", expand=False))
|
|
86
|
-
return choose_from_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default,
|
|
104
|
+
return choose_from_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default, tv=tv, multi=multi, custom_input=custom_input)
|
|
87
105
|
except (TypeError, ValueError) as te: # int(choice_string) failed due to # either the number is invalid, or the input is custom.
|
|
88
106
|
if choice_string in options_strings: # string input
|
|
89
107
|
choice_idx = options_strings.index(choice_one) # type: ignore
|
|
@@ -94,7 +112,7 @@ def choose_from_options[T](msg: str, options: Iterable[T], multi: bool, custom_i
|
|
|
94
112
|
_ = te
|
|
95
113
|
# raise ValueError(f"Unknown choice. {choice_string}") from te
|
|
96
114
|
console.print(Panel(f"❓ Unknown choice: '{choice_string}'", title="Error", expand=False))
|
|
97
|
-
return choose_from_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default,
|
|
115
|
+
return choose_from_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default, tv=tv, multi=multi, custom_input=custom_input)
|
|
98
116
|
console.print(Panel(f"✅ Selected option {choice_idx}: {choice_one}", title="Selected", expand=False))
|
|
99
117
|
if multi:
|
|
100
118
|
return [choice_one]
|
|
@@ -113,7 +131,7 @@ def choose_cloud_interactively() -> str:
|
|
|
113
131
|
raise ValueError(f"Got {tmp} from rclone listremotes")
|
|
114
132
|
if len(remotes) == 0:
|
|
115
133
|
raise RuntimeError("You don't have remotes. Configure your rclone first to get cloud services access.")
|
|
116
|
-
cloud: str = choose_from_options(msg="WHICH CLOUD?", multi=False, options=list(remotes), default=remotes[0],
|
|
134
|
+
cloud: str = choose_from_options(msg="WHICH CLOUD?", multi=False, options=list(remotes), default=remotes[0], tv=True)
|
|
117
135
|
console.print(Panel(f"✅ SELECTED CLOUD | {cloud}", border_style="bold blue", expand=False))
|
|
118
136
|
return cloud
|
|
119
137
|
|
|
@@ -131,4 +149,4 @@ def choose_ssh_host(multi: Literal[False]) -> str: ...
|
|
|
131
149
|
@overload
|
|
132
150
|
def choose_ssh_host(multi: Literal[True]) -> list[str]: ...
|
|
133
151
|
def choose_ssh_host(multi: bool):
|
|
134
|
-
return choose_from_options(msg="", options=get_ssh_hosts(), multi=multi,
|
|
152
|
+
return choose_from_options(msg="", options=get_ssh_hosts(), multi=multi, tv=True)
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
#!/usr/bin/env python3
|
|
4
|
+
import base64
|
|
5
|
+
import pathlib
|
|
6
|
+
import subprocess
|
|
7
|
+
import tempfile
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def main(options_to_preview_mapping: dict[str, str]) -> str | None:
|
|
12
|
+
keys = list(options_to_preview_mapping.keys())
|
|
13
|
+
if not keys:
|
|
14
|
+
return None
|
|
15
|
+
with tempfile.TemporaryDirectory(prefix="tv_channel_") as tmpdir:
|
|
16
|
+
tempdir = pathlib.Path(tmpdir)
|
|
17
|
+
entries: list[str] = []
|
|
18
|
+
index_map: dict[int, str] = {}
|
|
19
|
+
preview_map_path = tempdir / "previews.tsv"
|
|
20
|
+
preview_rows: list[str] = []
|
|
21
|
+
for idx, key in enumerate(keys):
|
|
22
|
+
display_key = key.replace("\t", " ").replace("\n", " ")
|
|
23
|
+
entries.append(f"{idx}\t{display_key}")
|
|
24
|
+
index_map[idx] = key
|
|
25
|
+
encoded_preview = base64.b64encode(options_to_preview_mapping[key].encode("utf-8")).decode("ascii")
|
|
26
|
+
preview_rows.append(f"{idx}\t{encoded_preview}")
|
|
27
|
+
preview_map_path.write_text("\n".join(preview_rows), encoding="utf-8")
|
|
28
|
+
entries_path = tempdir / "entries.tsv"
|
|
29
|
+
entries_path.write_text("\n".join(entries), encoding="utf-8")
|
|
30
|
+
preview_script = tempdir / "preview.sh"
|
|
31
|
+
preview_script.write_text(
|
|
32
|
+
"""#!/usr/bin/env bash
|
|
33
|
+
set -euo pipefail
|
|
34
|
+
|
|
35
|
+
idx="$1"
|
|
36
|
+
script_dir="$(cd -- "$(dirname -- "$0")" && pwd)"
|
|
37
|
+
previews_file="${script_dir}/previews.tsv"
|
|
38
|
+
|
|
39
|
+
if [[ ! -f "${previews_file}" ]]; then
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
encoded_preview="$(awk -F '\t' -v idx="${idx}" '($1==idx){print $2; exit}' "${previews_file}" || true)"
|
|
44
|
+
|
|
45
|
+
if [[ -z "${encoded_preview}" ]]; then
|
|
46
|
+
exit 0
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
preview_content="$(printf '%s' "${encoded_preview}" | base64 --decode)"
|
|
50
|
+
|
|
51
|
+
if command -v bat >/dev/null 2>&1; then
|
|
52
|
+
printf '%s' "${preview_content}" | glow -
|
|
53
|
+
elif command -v bat >/dev/null 2>&1; then
|
|
54
|
+
printf '%s' "${preview_content}" | bat --language=markdown --color=always --style=plain --paging=never
|
|
55
|
+
elif command -v glow >/dev/null 2>&1; then
|
|
56
|
+
printf '%s' "${preview_content}" | glow -
|
|
57
|
+
else
|
|
58
|
+
printf '%s' "${preview_content}"
|
|
59
|
+
fi
|
|
60
|
+
""",
|
|
61
|
+
encoding="utf-8"
|
|
62
|
+
)
|
|
63
|
+
preview_script.chmod(0o755)
|
|
64
|
+
channel_config = f"""[metadata]
|
|
65
|
+
name = "temp_options"
|
|
66
|
+
description = "Temporary channel for selecting options"
|
|
67
|
+
|
|
68
|
+
[source]
|
|
69
|
+
command = "cat '{entries_path}'"
|
|
70
|
+
display = "{{split:\\t:1}}"
|
|
71
|
+
output = "{{split:\\t:0}}"
|
|
72
|
+
|
|
73
|
+
[preview]
|
|
74
|
+
command = "{preview_script} {{split:\\t:0}}"
|
|
75
|
+
|
|
76
|
+
[ui.preview_panel]
|
|
77
|
+
size = 50
|
|
78
|
+
"""
|
|
79
|
+
channel_path = tempdir / "temp_options.toml"
|
|
80
|
+
channel_path.write_text(channel_config, encoding="utf-8")
|
|
81
|
+
env = os.environ.copy()
|
|
82
|
+
tv_config_dir = pathlib.Path.home() / ".config" / "television"
|
|
83
|
+
if not tv_config_dir.exists():
|
|
84
|
+
tv_config_dir = pathlib.Path(os.getenv("XDG_CONFIG_HOME", str(pathlib.Path.home() / ".config"))) / "television"
|
|
85
|
+
cable_dir = tv_config_dir / "cable"
|
|
86
|
+
cable_dir.mkdir(parents=True, exist_ok=True)
|
|
87
|
+
temp_channel_link = cable_dir / "temp_options.toml"
|
|
88
|
+
if temp_channel_link.exists() or temp_channel_link.is_symlink():
|
|
89
|
+
temp_channel_link.unlink()
|
|
90
|
+
temp_channel_link.symlink_to(channel_path)
|
|
91
|
+
output_file = tempdir / "selection.txt"
|
|
92
|
+
try:
|
|
93
|
+
result = subprocess.run(["tv", "temp_options"], check=False, stdout=output_file.open("w"), text=True, env=env)
|
|
94
|
+
finally:
|
|
95
|
+
if temp_channel_link.exists() or temp_channel_link.is_symlink():
|
|
96
|
+
temp_channel_link.unlink()
|
|
97
|
+
if result.returncode not in (0, 130):
|
|
98
|
+
raise SystemExit(result.returncode)
|
|
99
|
+
if result.returncode == 130:
|
|
100
|
+
return None
|
|
101
|
+
if not output_file.exists():
|
|
102
|
+
return None
|
|
103
|
+
selected = output_file.read_text().strip()
|
|
104
|
+
if not selected:
|
|
105
|
+
return None
|
|
106
|
+
try:
|
|
107
|
+
index = int(selected)
|
|
108
|
+
except ValueError:
|
|
109
|
+
return None
|
|
110
|
+
return index_map.get(index)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
if __name__ == "__main__":
|
|
114
|
+
demo_mapping = {
|
|
115
|
+
"Option 1": "# Option 1\nThis is the preview for option 1.",
|
|
116
|
+
"Option 2": "# Option 2\nThis is the preview for option 2.",
|
|
117
|
+
"Option 3": "# Option 3\nThis is the preview for option 3."
|
|
118
|
+
}
|
|
119
|
+
main(demo_mapping)
|