machineconfig 2.0__py3-none-any.whl ā 2.2__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/cloud_manager.py +0 -3
- machineconfig/cluster/data_transfer.py +0 -1
- machineconfig/cluster/file_manager.py +0 -1
- machineconfig/cluster/job_params.py +0 -3
- machineconfig/cluster/loader_runner.py +0 -3
- machineconfig/cluster/remote_machine.py +0 -1
- machineconfig/cluster/script_notify_upon_completion.py +0 -1
- machineconfig/cluster/sessions_managers/archive/create_zellij_template.py +5 -6
- machineconfig/cluster/sessions_managers/archive/session_managers.py +0 -1
- machineconfig/cluster/sessions_managers/enhanced_command_runner.py +17 -57
- machineconfig/cluster/sessions_managers/wt_local.py +36 -110
- machineconfig/cluster/sessions_managers/wt_local_manager.py +42 -112
- machineconfig/cluster/sessions_managers/wt_remote.py +23 -30
- machineconfig/cluster/sessions_managers/wt_remote_manager.py +20 -62
- machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +10 -15
- machineconfig/cluster/sessions_managers/wt_utils/process_monitor.py +27 -127
- machineconfig/cluster/sessions_managers/wt_utils/remote_executor.py +10 -43
- machineconfig/cluster/sessions_managers/wt_utils/session_manager.py +22 -101
- machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +11 -39
- machineconfig/cluster/sessions_managers/zellij_local.py +49 -102
- machineconfig/cluster/sessions_managers/zellij_local_manager.py +34 -78
- machineconfig/cluster/sessions_managers/zellij_remote.py +17 -24
- machineconfig/cluster/sessions_managers/zellij_remote_manager.py +7 -13
- machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +4 -2
- machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +6 -6
- machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +18 -88
- machineconfig/cluster/sessions_managers/zellij_utils/remote_executor.py +2 -6
- machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +12 -40
- machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +3 -2
- machineconfig/cluster/templates/cli_click.py +0 -1
- machineconfig/cluster/templates/cli_gooey.py +0 -2
- machineconfig/cluster/templates/cli_trogon.py +0 -1
- machineconfig/cluster/templates/run_cloud.py +0 -1
- machineconfig/cluster/templates/run_cluster.py +0 -1
- machineconfig/cluster/templates/run_remote.py +0 -1
- machineconfig/cluster/templates/utils.py +27 -46
- machineconfig/jobs/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/linux/msc/cli_agents.sh +16 -0
- machineconfig/jobs/python/check_installations.py +2 -1
- machineconfig/jobs/python/create_bootable_media.py +0 -2
- machineconfig/jobs/python/python_ve_symlink.py +9 -11
- machineconfig/jobs/python/tasks.py +0 -1
- machineconfig/jobs/python/vscode/api.py +5 -5
- machineconfig/jobs/python/vscode/link_ve.py +13 -14
- machineconfig/jobs/python/vscode/select_interpreter.py +21 -22
- machineconfig/jobs/python/vscode/sync_code.py +9 -13
- machineconfig/jobs/python_custom_installers/archive/ngrok.py +13 -13
- machineconfig/jobs/python_custom_installers/dev/aider.py +7 -15
- machineconfig/jobs/python_custom_installers/dev/alacritty.py +9 -18
- machineconfig/jobs/python_custom_installers/dev/brave.py +10 -19
- machineconfig/jobs/python_custom_installers/dev/bypass_paywall.py +8 -15
- machineconfig/jobs/python_custom_installers/dev/code.py +12 -32
- machineconfig/jobs/python_custom_installers/dev/cursor.py +3 -14
- machineconfig/jobs/python_custom_installers/dev/docker_desktop.py +8 -7
- machineconfig/jobs/python_custom_installers/dev/espanso.py +15 -19
- machineconfig/jobs/python_custom_installers/dev/goes.py +5 -12
- machineconfig/jobs/python_custom_installers/dev/lvim.py +9 -17
- machineconfig/jobs/python_custom_installers/dev/nerdfont.py +12 -19
- machineconfig/jobs/python_custom_installers/dev/redis.py +12 -20
- machineconfig/jobs/python_custom_installers/dev/wezterm.py +12 -19
- machineconfig/jobs/python_custom_installers/dev/winget.py +5 -23
- machineconfig/jobs/python_custom_installers/docker.py +12 -21
- machineconfig/jobs/python_custom_installers/gh.py +11 -19
- machineconfig/jobs/python_custom_installers/hx.py +32 -16
- machineconfig/jobs/python_custom_installers/warp-cli.py +12 -20
- machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_generic_installers/config.json +1 -1
- machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +1 -1
- machineconfig/jobs/windows/msc/cli_agents.bat +0 -0
- machineconfig/jobs/windows/msc/cli_agents.ps1 +0 -0
- machineconfig/jobs/windows/start_terminal.ps1 +1 -1
- machineconfig/profile/create.py +38 -26
- machineconfig/profile/create_hardlinks.py +29 -20
- machineconfig/profile/shell.py +56 -32
- machineconfig/scripts/__init__.py +0 -2
- machineconfig/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/cloud/init.sh +2 -2
- machineconfig/scripts/linux/checkout_versions +1 -1
- machineconfig/scripts/linux/choose_wezterm_theme +1 -1
- machineconfig/scripts/linux/cloud_copy +1 -1
- machineconfig/scripts/linux/cloud_manager +1 -1
- machineconfig/scripts/linux/cloud_mount +1 -1
- machineconfig/scripts/linux/cloud_repo_sync +1 -1
- machineconfig/scripts/linux/cloud_sync +1 -1
- machineconfig/scripts/linux/croshell +1 -1
- machineconfig/scripts/linux/devops +7 -7
- machineconfig/scripts/linux/fire +1 -1
- machineconfig/scripts/linux/fire_agents +3 -2
- machineconfig/scripts/linux/ftpx +1 -1
- machineconfig/scripts/linux/gh_models +1 -1
- machineconfig/scripts/linux/kill_process +1 -1
- machineconfig/scripts/linux/mcinit +1 -1
- machineconfig/scripts/linux/repos +1 -1
- machineconfig/scripts/linux/scheduler +1 -1
- machineconfig/scripts/linux/start_slidev +1 -1
- machineconfig/scripts/linux/start_terminals +1 -1
- machineconfig/scripts/linux/url2md +1 -1
- machineconfig/scripts/linux/warp-cli.sh +122 -0
- machineconfig/scripts/linux/wifi_conn +1 -1
- machineconfig/scripts/python/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_agents.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/__init__.py +0 -0
- machineconfig/scripts/python/ai/generate_files.py +83 -0
- machineconfig/scripts/python/ai/instructions/python/dev.instructions.md +2 -2
- machineconfig/scripts/python/ai/mcinit.py +14 -7
- machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +10 -5
- machineconfig/scripts/python/archive/tmate_conn.py +5 -5
- machineconfig/scripts/python/archive/tmate_start.py +7 -7
- machineconfig/scripts/python/choose_wezterm_theme.py +35 -32
- machineconfig/scripts/python/cloud_copy.py +23 -14
- machineconfig/scripts/python/cloud_mount.py +36 -24
- machineconfig/scripts/python/cloud_repo_sync.py +40 -27
- machineconfig/scripts/python/cloud_sync.py +4 -4
- machineconfig/scripts/python/croshell.py +40 -29
- machineconfig/scripts/python/devops.py +45 -27
- machineconfig/scripts/python/devops_add_identity.py +15 -25
- machineconfig/scripts/python/devops_add_ssh_key.py +8 -8
- machineconfig/scripts/python/devops_backup_retrieve.py +18 -16
- machineconfig/scripts/python/devops_devapps_install.py +25 -20
- machineconfig/scripts/python/devops_update_repos.py +232 -59
- machineconfig/scripts/python/dotfile.py +17 -15
- machineconfig/scripts/python/fire_agents.py +48 -22
- machineconfig/scripts/python/fire_jobs.py +93 -58
- machineconfig/scripts/python/ftpx.py +26 -15
- machineconfig/scripts/python/get_zellij_cmd.py +8 -7
- machineconfig/scripts/python/helpers/cloud_helpers.py +33 -28
- machineconfig/scripts/python/helpers/helpers2.py +27 -16
- machineconfig/scripts/python/helpers/helpers4.py +45 -32
- machineconfig/scripts/python/helpers/helpers5.py +1 -1
- machineconfig/scripts/python/helpers/repo_sync_helpers.py +32 -10
- machineconfig/scripts/python/mount_nfs.py +9 -16
- machineconfig/scripts/python/mount_nw_drive.py +10 -5
- machineconfig/scripts/python/mount_ssh.py +9 -7
- machineconfig/scripts/python/repos.py +216 -58
- machineconfig/scripts/python/snapshot.py +0 -1
- machineconfig/scripts/python/start_slidev.py +11 -6
- machineconfig/scripts/python/start_terminals.py +22 -16
- machineconfig/scripts/python/viewer_template.py +0 -1
- machineconfig/scripts/python/wifi_conn.py +49 -75
- machineconfig/scripts/python/wsl_windows_transfer.py +9 -7
- machineconfig/scripts/windows/checkout_version.ps1 +1 -3
- machineconfig/scripts/windows/choose_wezterm_theme.ps1 +1 -3
- machineconfig/scripts/windows/cloud_copy.ps1 +2 -6
- machineconfig/scripts/windows/cloud_manager.ps1 +1 -1
- machineconfig/scripts/windows/cloud_repo_sync.ps1 +1 -2
- machineconfig/scripts/windows/cloud_sync.ps1 +2 -2
- machineconfig/scripts/windows/croshell.ps1 +2 -2
- machineconfig/scripts/windows/devops.ps1 +1 -4
- machineconfig/scripts/windows/dotfile.ps1 +1 -3
- machineconfig/scripts/windows/fire.ps1 +1 -1
- machineconfig/scripts/windows/ftpx.ps1 +2 -2
- machineconfig/scripts/windows/gpt.ps1 +1 -1
- machineconfig/scripts/windows/kill_process.ps1 +1 -2
- machineconfig/scripts/windows/mcinit.ps1 +1 -1
- machineconfig/scripts/windows/mount_nfs.ps1 +1 -1
- machineconfig/scripts/windows/mount_ssh.ps1 +1 -1
- machineconfig/scripts/windows/pomodoro.ps1 +1 -1
- machineconfig/scripts/windows/py2exe.ps1 +1 -3
- machineconfig/scripts/windows/repos.ps1 +1 -1
- machineconfig/scripts/windows/scheduler.ps1 +1 -1
- machineconfig/scripts/windows/snapshot.ps1 +2 -2
- machineconfig/scripts/windows/start_slidev.ps1 +1 -1
- machineconfig/scripts/windows/start_terminals.ps1 +1 -1
- machineconfig/scripts/windows/wifi_conn.ps1 +1 -1
- machineconfig/scripts/windows/wsl_windows_transfer.ps1 +1 -3
- machineconfig/settings/lf/linux/lfrc +2 -1
- machineconfig/settings/linters/.ruff_cache/.gitignore +2 -0
- machineconfig/settings/linters/.ruff_cache/CACHEDIR.TAG +1 -0
- machineconfig/settings/lvim/windows/archive/config_additional.lua +1 -1
- machineconfig/settings/svim/linux/init.toml +1 -1
- machineconfig/settings/svim/windows/init.toml +1 -1
- machineconfig/setup_linux/web_shortcuts/croshell.sh +3 -52
- machineconfig/setup_linux/web_shortcuts/interactive.sh +6 -6
- machineconfig/setup_linux/web_shortcuts/ssh.sh +0 -4
- machineconfig/setup_windows/web_shortcuts/all.ps1 +2 -2
- machineconfig/setup_windows/web_shortcuts/ascii_art.ps1 +1 -1
- machineconfig/setup_windows/web_shortcuts/croshell.ps1 +1 -1
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +5 -5
- machineconfig/setup_windows/wt_and_pwsh/install_fonts.ps1 +51 -15
- machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +58 -13
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +45 -37
- machineconfig/utils/ai/generate_file_checklist.py +8 -10
- machineconfig/utils/ai/url2md.py +4 -2
- machineconfig/utils/cloud/onedrive/setup_oauth.py +1 -0
- machineconfig/utils/cloud/onedrive/transaction.py +63 -98
- machineconfig/utils/code.py +62 -41
- machineconfig/utils/installer.py +29 -35
- machineconfig/utils/installer_utils/installer_abc.py +11 -11
- machineconfig/utils/installer_utils/installer_class.py +155 -74
- machineconfig/utils/links.py +112 -31
- machineconfig/utils/notifications.py +211 -0
- machineconfig/utils/options.py +41 -42
- machineconfig/utils/path.py +13 -6
- machineconfig/utils/path_reduced.py +614 -311
- machineconfig/utils/procs.py +48 -42
- machineconfig/utils/scheduling.py +0 -1
- machineconfig/utils/source_of_truth.py +27 -0
- machineconfig/utils/ssh.py +146 -85
- machineconfig/utils/terminal.py +84 -37
- machineconfig/utils/upgrade_packages.py +91 -0
- machineconfig/utils/utils2.py +39 -50
- machineconfig/utils/utils5.py +195 -116
- machineconfig/utils/ve.py +13 -5
- {machineconfig-2.0.dist-info ā machineconfig-2.2.dist-info}/METADATA +14 -13
- {machineconfig-2.0.dist-info ā machineconfig-2.2.dist-info}/RECORD +212 -237
- machineconfig/jobs/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python/__pycache__/python_ve_symlink.cpython-311.pyc +0 -0
- machineconfig/jobs/python/archive/python_tools.txt +0 -12
- machineconfig/jobs/python/vscode/__pycache__/select_interpreter.cpython-311.pyc +0 -0
- machineconfig/jobs/python_custom_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python_generic_installers/update.py +0 -3
- machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/profile/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/profile/__pycache__/create.cpython-311.pyc +0 -0
- machineconfig/profile/__pycache__/shell.cpython-311.pyc +0 -0
- machineconfig/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/linux/activate_ve +0 -87
- machineconfig/scripts/python/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_copy.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_mount.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_sync.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/croshell.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_backup_retrieve.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_agents.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_jobs.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_jobs.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/get_zellij_cmd.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/repos.cpython-311.pyc +0 -0
- machineconfig/scripts/python/ai/__pycache__/init.cpython-311.pyc +0 -0
- machineconfig/scripts/python/ai/__pycache__/mcinit.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/cloud_helpers.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers2.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-313.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/repo_sync_helpers.cpython-311.pyc +0 -0
- machineconfig/scripts/windows/activate_ve.ps1 +0 -54
- machineconfig/setup_linux/web_shortcuts/all.sh +0 -48
- machineconfig/setup_linux/web_shortcuts/update_system.sh +0 -48
- machineconfig/utils/utils.py +0 -95
- /machineconfig/setup_linux/web_shortcuts/{tmp.sh ā android.sh} +0 -0
- {machineconfig-2.0.dist-info ā machineconfig-2.2.dist-info}/WHEEL +0 -0
- {machineconfig-2.0.dist-info ā machineconfig-2.2.dist-info}/top_level.txt +0 -0
machineconfig/utils/installer.py
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
"""package manager
|
|
2
|
-
|
|
1
|
+
"""package manager"""
|
|
2
|
+
|
|
3
3
|
from machineconfig.utils.installer_utils.installer_abc import LINUX_INSTALL_PATH, CATEGORY
|
|
4
4
|
from machineconfig.utils.installer_utils.installer_class import Installer
|
|
5
5
|
from rich.console import Console
|
|
6
|
-
from rich.panel import Panel
|
|
6
|
+
from rich.panel import Panel # Added import
|
|
7
7
|
|
|
8
|
-
from machineconfig.utils.path_reduced import
|
|
9
|
-
from machineconfig.utils.
|
|
8
|
+
from machineconfig.utils.path_reduced import PathExtended as PathExtended
|
|
9
|
+
from machineconfig.utils.source_of_truth import INSTALL_VERSION_ROOT
|
|
10
10
|
from machineconfig.utils.utils2 import read_json
|
|
11
11
|
|
|
12
12
|
# from dataclasses import dataclass
|
|
@@ -16,8 +16,8 @@ from joblib import Parallel, delayed
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
def check_latest():
|
|
19
|
-
console = Console()
|
|
20
|
-
console.print(Panel("š CHECKING FOR LATEST VERSIONS", title="Status", expand=False))
|
|
19
|
+
console = Console() # Added console initialization
|
|
20
|
+
console.print(Panel("š CHECKING FOR LATEST VERSIONS", title="Status", expand=False)) # Replaced print with Panel
|
|
21
21
|
installers = get_installers(system=platform.system(), dev=False)
|
|
22
22
|
# installers += get_installers(system=platform.system(), dev=True)
|
|
23
23
|
installers_github = []
|
|
@@ -46,12 +46,7 @@ def check_latest():
|
|
|
46
46
|
# Convert to list of dictionaries and group by status
|
|
47
47
|
result_data = []
|
|
48
48
|
for tool, status, current_ver, new_ver in res:
|
|
49
|
-
result_data.append({
|
|
50
|
-
"Tool": tool,
|
|
51
|
-
"Status": status,
|
|
52
|
-
"Current Version": current_ver,
|
|
53
|
-
"New Version": new_ver
|
|
54
|
-
})
|
|
49
|
+
result_data.append({"Tool": tool, "Status": status, "Current Version": current_ver, "New Version": new_ver})
|
|
55
50
|
|
|
56
51
|
# Group by status
|
|
57
52
|
grouped_data: dict[str, list[dict[str, Any]]] = {}
|
|
@@ -70,11 +65,11 @@ def check_latest():
|
|
|
70
65
|
for item in items:
|
|
71
66
|
print(f" {item['Tool']:<20} | Current: {item['Current Version']:<15} | New: {item['New Version']}")
|
|
72
67
|
print("-" * 60)
|
|
73
|
-
print(f"{'ā'*80}")
|
|
68
|
+
print(f"{'ā' * 80}")
|
|
74
69
|
|
|
75
70
|
|
|
76
71
|
def get_installed_cli_apps():
|
|
77
|
-
print(f"\n{'='*80}\nš LISTING INSTALLED CLI APPS š\n{'='*80}")
|
|
72
|
+
print(f"\n{'=' * 80}\nš LISTING INSTALLED CLI APPS š\n{'=' * 80}")
|
|
78
73
|
if platform.system() == "Windows":
|
|
79
74
|
print("šŖ Searching for Windows executables...")
|
|
80
75
|
apps = PathExtended.home().joinpath("AppData/Local/Microsoft/WindowsApps").search("*.exe", not_in=["notepad"])
|
|
@@ -89,12 +84,12 @@ def get_installed_cli_apps():
|
|
|
89
84
|
print(error_msg)
|
|
90
85
|
raise NotImplementedError(error_msg)
|
|
91
86
|
apps = [app for app in apps if app.size("kb") > 0.1 and not app.is_symlink()] # no symlinks like paint and wsl and bash
|
|
92
|
-
print(f"ā
Found {len(apps)} installed applications\n{'='*80}")
|
|
87
|
+
print(f"ā
Found {len(apps)} installed applications\n{'=' * 80}")
|
|
93
88
|
return apps
|
|
94
89
|
|
|
95
90
|
|
|
96
91
|
def get_installers(system: str, dev: bool) -> list[Installer]:
|
|
97
|
-
print(f"\n{'='*80}\nš LOADING INSTALLER CONFIGURATIONS š\n{'='*80}")
|
|
92
|
+
print(f"\n{'=' * 80}\nš LOADING INSTALLER CONFIGURATIONS š\n{'=' * 80}")
|
|
98
93
|
res_all = get_all_dicts(system=system)
|
|
99
94
|
if not dev:
|
|
100
95
|
print("ā¹ļø Excluding development installers...")
|
|
@@ -104,12 +99,12 @@ def get_installers(system: str, dev: bool) -> list[Installer]:
|
|
|
104
99
|
res_final = {}
|
|
105
100
|
for _k, v in res_all.items():
|
|
106
101
|
res_final.update(v)
|
|
107
|
-
print(f"ā
Loaded {len(res_final)} installer configurations\n{'='*80}")
|
|
102
|
+
print(f"ā
Loaded {len(res_final)} installer configurations\n{'=' * 80}")
|
|
108
103
|
return [Installer.from_dict(d=vd, name=k) for k, vd in res_final.items()]
|
|
109
104
|
|
|
110
105
|
|
|
111
106
|
def get_all_dicts(system: str) -> dict[CATEGORY, dict[str, dict[str, Any]]]:
|
|
112
|
-
print(f"\n{'='*80}\nš LOADING CONFIGURATION FILES š\n{'='*80}")
|
|
107
|
+
print(f"\n{'=' * 80}\nš LOADING CONFIGURATION FILES š\n{'=' * 80}")
|
|
113
108
|
|
|
114
109
|
print(f"š Importing OS-specific installers for {system}...")
|
|
115
110
|
if system == "Windows":
|
|
@@ -119,6 +114,7 @@ def get_all_dicts(system: str) -> dict[CATEGORY, dict[str, dict[str, Any]]]:
|
|
|
119
114
|
|
|
120
115
|
print("š Importing generic installers...")
|
|
121
116
|
import machineconfig.jobs.python_generic_installers as generic_installer
|
|
117
|
+
|
|
122
118
|
path_os_specific = PathExtended(os_specific_installer.__file__).parent
|
|
123
119
|
path_os_generic = PathExtended(generic_installer.__file__).parent
|
|
124
120
|
|
|
@@ -127,7 +123,7 @@ def get_all_dicts(system: str) -> dict[CATEGORY, dict[str, dict[str, Any]]]:
|
|
|
127
123
|
|
|
128
124
|
print("š Loading configuration files...")
|
|
129
125
|
res_final: dict[CATEGORY, dict[str, dict[str, Any]]] = {}
|
|
130
|
-
print(f"""š Loading OS-specific config from: {path_os_specific.joinpath(
|
|
126
|
+
print(f"""š Loading OS-specific config from: {path_os_specific.joinpath("config.json")}""")
|
|
131
127
|
res_final["OS_SPECIFIC"] = read_json(path=path_os_specific.joinpath("config.json"))
|
|
132
128
|
|
|
133
129
|
print(f"""š Loading OS-generic config from: {path_os_generic.joinpath("config.json")}""")
|
|
@@ -144,11 +140,12 @@ def get_all_dicts(system: str) -> dict[CATEGORY, dict[str, dict[str, Any]]]:
|
|
|
144
140
|
|
|
145
141
|
print(f"š Loading custom installers from: {path_custom_installer}")
|
|
146
142
|
import runpy
|
|
143
|
+
|
|
147
144
|
res_custom: dict[str, dict[str, Any]] = {}
|
|
148
145
|
for item in path_custom_installer.search("*.py", r=False, not_in=["__init__"]):
|
|
149
146
|
try:
|
|
150
147
|
print(f"š Loading custom installer: {item.name}")
|
|
151
|
-
config_dict = runpy.run_path(str(item), run_name=None)[
|
|
148
|
+
config_dict = runpy.run_path(str(item), run_name=None)["config_dict"]
|
|
152
149
|
res_custom[item.stem] = config_dict
|
|
153
150
|
except Exception as ex:
|
|
154
151
|
print(f"ā Failed to load {item}: {ex}")
|
|
@@ -158,7 +155,7 @@ def get_all_dicts(system: str) -> dict[CATEGORY, dict[str, dict[str, Any]]]:
|
|
|
158
155
|
for item in path_custom_installer_dev.search("*.py", r=False, not_in=["__init__"]):
|
|
159
156
|
try:
|
|
160
157
|
print(f"š Loading custom dev installer: {item.name}")
|
|
161
|
-
config_dict = runpy.run_path(str(item), run_name=None)[
|
|
158
|
+
config_dict = runpy.run_path(str(item), run_name=None)["config_dict"]
|
|
162
159
|
res_custom_dev[item.stem] = config_dict
|
|
163
160
|
except Exception as ex:
|
|
164
161
|
print(f"ā Failed to load {item}: {ex}")
|
|
@@ -166,15 +163,15 @@ def get_all_dicts(system: str) -> dict[CATEGORY, dict[str, dict[str, Any]]]:
|
|
|
166
163
|
res_final["CUSTOM"] = res_custom
|
|
167
164
|
res_final["CUSTOM_DEV"] = res_custom_dev
|
|
168
165
|
|
|
169
|
-
print(f"ā
Configuration loading complete:\n - OS_SPECIFIC: {len(res_final['OS_SPECIFIC'])} items\n - OS_GENERIC: {len(res_final['OS_GENERIC'])} items\n - CUSTOM: {len(res_final['CUSTOM'])} items\n{'='*80}")
|
|
166
|
+
print(f"ā
Configuration loading complete:\n - OS_SPECIFIC: {len(res_final['OS_SPECIFIC'])} items\n - OS_GENERIC: {len(res_final['OS_GENERIC'])} items\n - CUSTOM: {len(res_final['CUSTOM'])} items\n{'=' * 80}")
|
|
170
167
|
return res_final
|
|
171
168
|
|
|
172
169
|
|
|
173
|
-
def install_all(installers: list[Installer], safe: bool=False, jobs: int = 10, fresh: bool=False):
|
|
174
|
-
print(f"\n{'='*80}\nš BULK INSTALLATION PROCESS š\n{'='*80}")
|
|
170
|
+
def install_all(installers: list[Installer], safe: bool = False, jobs: int = 10, fresh: bool = False):
|
|
171
|
+
print(f"\n{'=' * 80}\nš BULK INSTALLATION PROCESS š\n{'=' * 80}")
|
|
175
172
|
if fresh:
|
|
176
173
|
print("š§¹ Fresh install requested - clearing version cache...")
|
|
177
|
-
INSTALL_VERSION_ROOT.delete(sure=True)
|
|
174
|
+
PathExtended(INSTALL_VERSION_ROOT).delete(sure=True)
|
|
178
175
|
print("ā
Version cache cleared")
|
|
179
176
|
|
|
180
177
|
if safe:
|
|
@@ -204,16 +201,13 @@ def install_all(installers: list[Installer], safe: bool=False, jobs: int = 10, f
|
|
|
204
201
|
# return None
|
|
205
202
|
|
|
206
203
|
print(f"š Starting installation of {len(installers)} packages...")
|
|
207
|
-
print(f"\n{'='*80}\nš¦ INSTALLING FIRST PACKAGE š¦\n{'='*80}")
|
|
204
|
+
print(f"\n{'=' * 80}\nš¦ INSTALLING FIRST PACKAGE š¦\n{'=' * 80}")
|
|
208
205
|
installers[0].install(version=None)
|
|
209
206
|
installers_remaining = installers[1:]
|
|
210
|
-
print(f"\n{'='*80}\nš¦ INSTALLING REMAINING PACKAGES š¦\n{'='*80}")
|
|
207
|
+
print(f"\n{'=' * 80}\nš¦ INSTALLING REMAINING PACKAGES š¦\n{'=' * 80}")
|
|
211
208
|
|
|
212
209
|
# Use joblib for parallel processing of remaining installers
|
|
213
|
-
res = Parallel(n_jobs=jobs)(
|
|
214
|
-
delayed(lambda x: x.install_robust(version=None))(installer)
|
|
215
|
-
for installer in installers_remaining
|
|
216
|
-
)
|
|
210
|
+
res = Parallel(n_jobs=jobs)(delayed(lambda x: x.install_robust(version=None))(installer) for installer in installers_remaining)
|
|
217
211
|
|
|
218
212
|
console = Console()
|
|
219
213
|
|
|
@@ -222,19 +216,19 @@ def install_all(installers: list[Installer], safe: bool=False, jobs: int = 10, f
|
|
|
222
216
|
|
|
223
217
|
print("\n")
|
|
224
218
|
console.rule("ā Same Version Apps")
|
|
225
|
-
same_version_results = [r for r in res if r and
|
|
219
|
+
same_version_results = [r for r in res if r and "same version" in str(r)]
|
|
226
220
|
for result in same_version_results:
|
|
227
221
|
print(f" {result}")
|
|
228
222
|
|
|
229
223
|
print("\n")
|
|
230
224
|
console.rule("ā¬ļø Updated Apps")
|
|
231
|
-
updated_results = [r for r in res if r and
|
|
225
|
+
updated_results = [r for r in res if r and "updated from" in str(r)]
|
|
232
226
|
for result in updated_results:
|
|
233
227
|
print(f" {result}")
|
|
234
228
|
|
|
235
229
|
print("\n")
|
|
236
230
|
console.rule("ā Failed Apps")
|
|
237
|
-
failed_results = [r for r in res if r and
|
|
231
|
+
failed_results = [r for r in res if r and "Failed at" in str(r)]
|
|
238
232
|
for result in failed_results:
|
|
239
233
|
print(f" {result}")
|
|
240
234
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
from machineconfig.utils.path_reduced import PathExtended as PathExtended
|
|
3
|
+
from machineconfig.utils.source_of_truth import WINDOWS_INSTALL_PATH, LINUX_INSTALL_PATH
|
|
2
4
|
from typing import Optional, TypeAlias, Literal
|
|
3
5
|
import subprocess
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
# LINUX_INSTALL_PATH = '~/.local/bin'
|
|
7
|
-
LINUX_INSTALL_PATH = PathExtended.home().joinpath(".local/bin").__str__()
|
|
8
|
-
WINDOWS_INSTALL_PATH = PathExtended.home().joinpath("AppData/Local/Microsoft/WindowsApps").__str__()
|
|
7
|
+
|
|
9
8
|
CATEGORY: TypeAlias = Literal["OS_SPECIFIC", "OS_GENERIC", "CUSTOM", "OS_SPECIFIC_DEV", "OS_GENERIC_DEV", "CUSTOM_DEV"]
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
def find_move_delete_windows(downloaded_file_path: PathExtended, exe_name: Optional[str] = None, delete: bool=True, rename_to: Optional[str] = None):
|
|
13
|
-
print(f"\n{'='*80}\nš PROCESSING WINDOWS EXECUTABLE š\n{'='*80}")
|
|
14
|
-
if exe_name is not None and ".exe" in exe_name:
|
|
11
|
+
def find_move_delete_windows(downloaded_file_path: PathExtended, exe_name: Optional[str] = None, delete: bool = True, rename_to: Optional[str] = None):
|
|
12
|
+
print(f"\n{'=' * 80}\nš PROCESSING WINDOWS EXECUTABLE š\n{'=' * 80}")
|
|
13
|
+
if exe_name is not None and ".exe" in exe_name:
|
|
14
|
+
exe_name = exe_name.replace(".exe", "")
|
|
15
15
|
if downloaded_file_path.is_file():
|
|
16
16
|
exe = downloaded_file_path
|
|
17
17
|
print(f"š Found direct executable file: {exe}")
|
|
@@ -49,12 +49,12 @@ def find_move_delete_windows(downloaded_file_path: PathExtended, exe_name: Optio
|
|
|
49
49
|
downloaded_file_path.delete(sure=True)
|
|
50
50
|
print("ā
Temporary files removed")
|
|
51
51
|
|
|
52
|
-
print(f"{'='*80}")
|
|
52
|
+
print(f"{'=' * 80}")
|
|
53
53
|
return exe_new_location
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
def find_move_delete_linux(downloaded: PathExtended, tool_name: str, delete: Optional[bool] = True, rename_to: Optional[str] = None):
|
|
57
|
-
print(f"\n{'='*80}\nš PROCESSING LINUX EXECUTABLE š\n{'='*80}")
|
|
57
|
+
print(f"\n{'=' * 80}\nš PROCESSING LINUX EXECUTABLE š\n{'=' * 80}")
|
|
58
58
|
if downloaded.is_file():
|
|
59
59
|
exe = downloaded
|
|
60
60
|
print(f"š Found direct executable file: {exe}")
|
|
@@ -108,5 +108,5 @@ def find_move_delete_linux(downloaded: PathExtended, tool_name: str, delete: Opt
|
|
|
108
108
|
print("ā
Temporary files removed")
|
|
109
109
|
|
|
110
110
|
exe_new_location = PathExtended(LINUX_INSTALL_PATH).joinpath(exe.name)
|
|
111
|
-
print(f"ā
Executable installed at: {exe_new_location}\n{'='*80}")
|
|
111
|
+
print(f"ā
Executable installed at: {exe_new_location}\n{'=' * 80}")
|
|
112
112
|
return exe_new_location
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
from machineconfig.utils.path_reduced import P as PathExtended
|
|
1
|
+
from machineconfig.utils.path_reduced import PathExtended as PathExtended
|
|
3
2
|
from machineconfig.utils.installer_utils.installer_abc import find_move_delete_linux, find_move_delete_windows
|
|
4
|
-
from machineconfig.utils.
|
|
3
|
+
from machineconfig.utils.source_of_truth import INSTALL_TMP_DIR, INSTALL_VERSION_ROOT, LIBRARY_ROOT
|
|
4
|
+
from machineconfig.utils.options import check_tool_exists
|
|
5
5
|
from machineconfig.utils.utils2 import pprint, read_json
|
|
6
6
|
|
|
7
7
|
import platform
|
|
@@ -11,45 +11,59 @@ from pathlib import Path
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class Installer:
|
|
14
|
-
def __init__(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
self.
|
|
29
|
-
self.
|
|
30
|
-
self.
|
|
31
|
-
self.
|
|
32
|
-
self.
|
|
33
|
-
self.
|
|
34
|
-
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
repo_url: str,
|
|
17
|
+
name: str,
|
|
18
|
+
doc: str,
|
|
19
|
+
strip_v: bool,
|
|
20
|
+
exe_name: str,
|
|
21
|
+
filename_template_windows_amd_64: str,
|
|
22
|
+
filename_template_linux_amd_64: str,
|
|
23
|
+
filename_template_windows_arm_64: Optional[str] = None,
|
|
24
|
+
filename_template_linux_arm_64: Optional[str] = None,
|
|
25
|
+
filename_template_macos_amd_64: Optional[str] = None,
|
|
26
|
+
filename_template_macos_arm_64: Optional[str] = None,
|
|
27
|
+
):
|
|
28
|
+
self.repo_url: str = repo_url
|
|
29
|
+
self.name: str = name
|
|
30
|
+
self.doc: str = doc
|
|
31
|
+
self.filename_template_windows_amd_64: str = filename_template_windows_amd_64
|
|
32
|
+
self.filename_template_windows_arm_64: Optional[str] = filename_template_windows_arm_64
|
|
33
|
+
self.filename_template_linux_arm_64: Optional[str] = filename_template_linux_arm_64
|
|
34
|
+
self.filename_template_linux_amd_64: str = filename_template_linux_amd_64
|
|
35
|
+
self.filename_template_macos_amd_64: Optional[str] = filename_template_macos_amd_64
|
|
36
|
+
self.filename_template_macos_arm_64: Optional[str] = filename_template_macos_arm_64
|
|
37
|
+
self.strip_v: bool = strip_v
|
|
38
|
+
self.exe_name: str = exe_name
|
|
39
|
+
|
|
40
|
+
def __repr__(self) -> str:
|
|
41
|
+
return f"Installer of {self.exe_name} {self.name} @ {self.repo_url}"
|
|
42
|
+
|
|
35
43
|
def get_description(self):
|
|
36
44
|
# old_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
|
|
37
45
|
# old_version_cli = os.system(f"{self.exe_name} --version").replace("\n", "")
|
|
38
|
-
old_version_cli: bool=check_tool_exists(tool_name=self.exe_name)
|
|
46
|
+
old_version_cli: bool = check_tool_exists(tool_name=self.exe_name)
|
|
39
47
|
old_version_cli_str = "ā
" if old_version_cli else "ā"
|
|
40
48
|
# name_version = f"{self.exe_name} {old_version_cli_str}"
|
|
41
49
|
return f"{self.exe_name:<12} {old_version_cli_str} {self.doc}"
|
|
42
|
-
|
|
50
|
+
|
|
51
|
+
def to_dict(self):
|
|
52
|
+
return self.__dict__
|
|
53
|
+
|
|
43
54
|
@staticmethod
|
|
44
55
|
def from_dict(d: dict[str, Any], name: str):
|
|
45
|
-
try:
|
|
56
|
+
try:
|
|
57
|
+
return Installer(name=name, **d)
|
|
46
58
|
except Exception as ex:
|
|
47
59
|
pprint(d, "Installer Creation Error")
|
|
48
60
|
raise ex
|
|
61
|
+
|
|
49
62
|
@staticmethod
|
|
50
63
|
def choose_app_and_install():
|
|
51
|
-
print(f"\n{'='*80}\nš SELECT APPLICATION TO INSTALL š\n{'='*80}")
|
|
52
|
-
from machineconfig.utils.
|
|
64
|
+
print(f"\n{'=' * 80}\nš SELECT APPLICATION TO INSTALL š\n{'=' * 80}")
|
|
65
|
+
from machineconfig.utils.options import choose_one_option
|
|
66
|
+
|
|
53
67
|
print("š Searching for configuration files...")
|
|
54
68
|
jobs_dir = Path(LIBRARY_ROOT.joinpath("jobs"))
|
|
55
69
|
config_paths = [Path(p) for p in jobs_dir.rglob("config.json")]
|
|
@@ -62,12 +76,12 @@ class Installer:
|
|
|
62
76
|
installer = Installer.from_dict(d=config[app_name], name=app_name)
|
|
63
77
|
print(f"š¦ Selected application: {installer.exe_name}")
|
|
64
78
|
version = input(f"š Enter version to install for {installer.exe_name} [latest]: ") or None
|
|
65
|
-
print(f"\n{'='*80}\nš INSTALLING {installer.exe_name.upper()} š\n{'='*80}")
|
|
79
|
+
print(f"\n{'=' * 80}\nš INSTALLING {installer.exe_name.upper()} š\n{'=' * 80}")
|
|
66
80
|
installer.install(version=version)
|
|
67
81
|
|
|
68
82
|
def install_robust(self, version: Optional[str]):
|
|
69
83
|
try:
|
|
70
|
-
print(f"\n{'='*80}\nš INSTALLING {self.exe_name.upper()} š\n{'='*80}")
|
|
84
|
+
print(f"\n{'=' * 80}\nš INSTALLING {self.exe_name.upper()} š\n{'=' * 80}")
|
|
71
85
|
result_old = subprocess.run(f"{self.exe_name} --version", shell=True, capture_output=True, text=True)
|
|
72
86
|
old_version_cli = result_old.stdout.strip()
|
|
73
87
|
print(f"š Current version: {old_version_cli or 'Not installed'}")
|
|
@@ -90,10 +104,11 @@ class Installer:
|
|
|
90
104
|
return f"""echo "š¦ļø ā Failed to install `{self.name}` with error: {ex}" """
|
|
91
105
|
|
|
92
106
|
def install(self, version: Optional[str]):
|
|
93
|
-
print(f"\n{'='*80}\nš§ INSTALLATION PROCESS: {self.exe_name} š§\n{'='*80}")
|
|
107
|
+
print(f"\n{'=' * 80}\nš§ INSTALLATION PROCESS: {self.exe_name} š§\n{'=' * 80}")
|
|
94
108
|
if self.repo_url == "CUSTOM":
|
|
95
109
|
print(f"š§© Using custom installer for {self.exe_name}")
|
|
96
110
|
import machineconfig.jobs.python_custom_installers as python_custom_installers
|
|
111
|
+
|
|
97
112
|
installer_path = Path(python_custom_installers.__file__).parent.joinpath(self.exe_name + ".py")
|
|
98
113
|
if not installer_path.exists():
|
|
99
114
|
installer_path = Path(python_custom_installers.__file__).parent.joinpath("dev", self.exe_name + ".py")
|
|
@@ -102,13 +117,17 @@ class Installer:
|
|
|
102
117
|
print(f"š Found installer at: {installer_path}")
|
|
103
118
|
|
|
104
119
|
import runpy
|
|
120
|
+
|
|
105
121
|
print(f"āļø Executing function 'main' from '{installer_path}'...")
|
|
106
|
-
program: str = runpy.run_path(str(installer_path), run_name=None)[
|
|
122
|
+
program: str = runpy.run_path(str(installer_path), run_name=None)["main"](version=version)
|
|
107
123
|
# print(program)
|
|
108
124
|
print("š Running installation script...")
|
|
109
|
-
if platform.system() == "Linux":
|
|
110
|
-
|
|
111
|
-
|
|
125
|
+
if platform.system() == "Linux":
|
|
126
|
+
script = "#!/bin/bash" + "\n" + program
|
|
127
|
+
else:
|
|
128
|
+
script = program
|
|
129
|
+
script_file = PathExtended.tmpfile(name="tmp_shell_script", suffix=".ps1" if platform.system() == "Windows" else ".sh", folder="tmp_scripts")
|
|
130
|
+
script_file.write_text(script, newline=None if platform.system() == "Windows" else "\n")
|
|
112
131
|
if platform.system() == "Windows":
|
|
113
132
|
start_cmd = "powershell"
|
|
114
133
|
full_command = f"{start_cmd} {script_file}"
|
|
@@ -117,7 +136,7 @@ class Installer:
|
|
|
117
136
|
full_command = f"{start_cmd} {script_file}"
|
|
118
137
|
subprocess.run(full_command, stdin=None, stdout=None, stderr=None, shell=True, text=True)
|
|
119
138
|
version_to_be_installed = str(version)
|
|
120
|
-
print(f"ā
Custom installation completed\n{'='*80}")
|
|
139
|
+
print(f"ā
Custom installation completed\n{'=' * 80}")
|
|
121
140
|
|
|
122
141
|
elif "npm " in self.repo_url or "pip " in self.repo_url or "winget " in self.repo_url:
|
|
123
142
|
package_manager = self.repo_url.split(" ", maxsplit=1)[0]
|
|
@@ -134,7 +153,7 @@ class Installer:
|
|
|
134
153
|
if result.stderr:
|
|
135
154
|
print(f"STDERR: {result.stderr}")
|
|
136
155
|
print(f"Return code: {result.returncode}")
|
|
137
|
-
print(f"ā
Package manager installation completed\n{'='*80}")
|
|
156
|
+
print(f"ā
Package manager installation completed\n{'=' * 80}")
|
|
138
157
|
|
|
139
158
|
else:
|
|
140
159
|
print("š„ Downloading from repository...")
|
|
@@ -154,7 +173,7 @@ class Installer:
|
|
|
154
173
|
print(f"Return code: {result.returncode}")
|
|
155
174
|
print("šļø Cleaning up .deb package...")
|
|
156
175
|
downloaded.delete(sure=True)
|
|
157
|
-
print(f"ā
DEB package installation completed\n{'='*80}")
|
|
176
|
+
print(f"ā
DEB package installation completed\n{'=' * 80}")
|
|
158
177
|
else:
|
|
159
178
|
if platform.system() == "Windows":
|
|
160
179
|
print("šŖ Installing on Windows...")
|
|
@@ -172,6 +191,7 @@ class Installer:
|
|
|
172
191
|
if exe.name.replace(".exe", "") != self.exe_name.replace(".exe", ""):
|
|
173
192
|
from rich import print as pprint
|
|
174
193
|
from rich.panel import Panel
|
|
194
|
+
|
|
175
195
|
print("ā ļø Warning: Executable name mismatch")
|
|
176
196
|
pprint(Panel(f"Expected exe name: [red]{self.exe_name}[/red] \nAttained name: [red]{exe.name.replace('.exe', '')}[/red]", title="exe name mismatch", subtitle=self.repo_url))
|
|
177
197
|
new_exe_name = self.exe_name + ".exe" if platform.system() == "Windows" else self.exe_name
|
|
@@ -181,30 +201,30 @@ class Installer:
|
|
|
181
201
|
print(f"š¾ Saving version information to: {INSTALL_VERSION_ROOT.joinpath(self.exe_name)}")
|
|
182
202
|
INSTALL_VERSION_ROOT.joinpath(self.exe_name).parent.mkdir(parents=True, exist_ok=True)
|
|
183
203
|
INSTALL_VERSION_ROOT.joinpath(self.exe_name).write_text(version_to_be_installed, encoding="utf-8")
|
|
184
|
-
print(f"ā
Installation completed successfully!\n{'='*80}")
|
|
204
|
+
print(f"ā
Installation completed successfully!\n{'=' * 80}")
|
|
185
205
|
|
|
186
206
|
def download(self, version: Optional[str]):
|
|
187
|
-
print(f"\n{'='*80}\nš„ DOWNLOADING: {self.exe_name} š„\n{'='*80}")
|
|
207
|
+
print(f"\n{'=' * 80}\nš„ DOWNLOADING: {self.exe_name} š„\n{'=' * 80}")
|
|
208
|
+
download_link: Optional[Path] = None
|
|
209
|
+
version_to_be_installed: Optional[str] = None
|
|
188
210
|
if "github" not in self.repo_url or ".zip" in self.repo_url or ".tar.gz" in self.repo_url:
|
|
189
211
|
download_link = Path(self.repo_url)
|
|
190
212
|
version_to_be_installed = "predefined_url"
|
|
191
213
|
print(f"š Using direct download URL: {download_link}")
|
|
192
214
|
print(f"š¦ Version to be installed: {version_to_be_installed}")
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
if
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
elif platform.system() in ["Linux", "Darwin"]:
|
|
199
|
-
download_link = Path(self.filename_template_linux_amd_64)
|
|
200
|
-
system_name = "Linux" if platform.system() == "Linux" else "macOS"
|
|
201
|
-
print(f"š§ Using {system_name}-specific download URL: {download_link}")
|
|
215
|
+
elif self._any_direct_http_template():
|
|
216
|
+
template, arch = self._select_template()
|
|
217
|
+
if not template.startswith("http"):
|
|
218
|
+
# Fall back to github-style handling below
|
|
219
|
+
pass
|
|
202
220
|
else:
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
221
|
+
download_link = Path(template)
|
|
222
|
+
version_to_be_installed = "predefined_url"
|
|
223
|
+
system_name = self._system_name()
|
|
224
|
+
print(f"š§ Detected system={system_name} arch={arch}")
|
|
225
|
+
print(f"š Using architecture-specific direct URL: {download_link}")
|
|
226
|
+
print(f"š¦ Version to be installed: {version_to_be_installed}")
|
|
227
|
+
# continue to unified download logic below
|
|
208
228
|
|
|
209
229
|
else:
|
|
210
230
|
print("š Retrieving release information from GitHub...")
|
|
@@ -215,36 +235,97 @@ class Installer:
|
|
|
215
235
|
version_to_be_installed_stripped = version_to_be_installed.replace("v", "") if self.strip_v else version_to_be_installed
|
|
216
236
|
version_to_be_installed_stripped = version_to_be_installed_stripped.replace("ipinfo-", "")
|
|
217
237
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
print(f"š§ {system_name} file name: {file_name}")
|
|
225
|
-
else:
|
|
226
|
-
error_msg = f"ā ERROR: System {platform.system()} not supported"
|
|
227
|
-
print(error_msg)
|
|
228
|
-
raise NotImplementedError(error_msg)
|
|
238
|
+
template, arch = self._select_template()
|
|
239
|
+
system_name = self._system_name()
|
|
240
|
+
file_name = template.format(version_to_be_installed_stripped)
|
|
241
|
+
print(f"š§ Detected system={system_name} arch={arch}")
|
|
242
|
+
print(f"š Using template: {template}")
|
|
243
|
+
print(f"šļø Resolved file name: {file_name}")
|
|
229
244
|
|
|
230
245
|
print(f"š File name: {file_name}")
|
|
231
246
|
download_link = release_url.joinpath(file_name)
|
|
232
247
|
|
|
248
|
+
assert download_link is not None, "download_link must be set"
|
|
249
|
+
assert version_to_be_installed is not None, "version_to_be_installed must be set"
|
|
233
250
|
print(f"š„ Downloading {self.name} from: {download_link}")
|
|
234
251
|
downloaded = PathExtended(download_link).download(folder=INSTALL_TMP_DIR).decompress()
|
|
235
|
-
print(f"ā
Download and extraction completed to: {downloaded}\n{'='*80}")
|
|
252
|
+
print(f"ā
Download and extraction completed to: {downloaded}\n{'=' * 80}")
|
|
236
253
|
return downloaded, version_to_be_installed
|
|
237
254
|
|
|
255
|
+
# --------------------------- Arch / template helpers ---------------------------
|
|
256
|
+
def _normalized_arch(self) -> str:
|
|
257
|
+
arch_raw = platform.machine().lower()
|
|
258
|
+
if arch_raw in ("x86_64", "amd64"):
|
|
259
|
+
return "amd64"
|
|
260
|
+
if arch_raw in ("aarch64", "arm64", "armv8", "armv8l"):
|
|
261
|
+
return "arm64"
|
|
262
|
+
return arch_raw
|
|
263
|
+
|
|
264
|
+
def _system_name(self) -> str:
|
|
265
|
+
sys_ = platform.system()
|
|
266
|
+
if sys_ == "Darwin":
|
|
267
|
+
return "macOS"
|
|
268
|
+
return sys_
|
|
269
|
+
|
|
270
|
+
def _any_direct_http_template(self) -> bool:
|
|
271
|
+
templates: list[Optional[str]] = [
|
|
272
|
+
self.filename_template_windows_amd_64,
|
|
273
|
+
self.filename_template_windows_arm_64,
|
|
274
|
+
self.filename_template_linux_amd_64,
|
|
275
|
+
self.filename_template_linux_arm_64,
|
|
276
|
+
self.filename_template_macos_amd_64,
|
|
277
|
+
self.filename_template_macos_arm_64,
|
|
278
|
+
]
|
|
279
|
+
return any(t for t in templates if t is not None and t.startswith("http"))
|
|
280
|
+
|
|
281
|
+
def _select_template(self) -> tuple[str, str]:
|
|
282
|
+
sys_name = platform.system()
|
|
283
|
+
arch = self._normalized_arch()
|
|
284
|
+
# mapping logic
|
|
285
|
+
candidates: list[str] = []
|
|
286
|
+
template: Optional[str] = None
|
|
287
|
+
if sys_name == "Windows":
|
|
288
|
+
if arch == "arm64" and self.filename_template_windows_arm_64:
|
|
289
|
+
template = self.filename_template_windows_arm_64
|
|
290
|
+
else:
|
|
291
|
+
template = self.filename_template_windows_amd_64
|
|
292
|
+
candidates = ["filename_template_windows_arm_64", "filename_template_windows_amd_64"]
|
|
293
|
+
elif sys_name == "Linux":
|
|
294
|
+
if arch == "arm64" and self.filename_template_linux_arm_64:
|
|
295
|
+
template = self.filename_template_linux_arm_64
|
|
296
|
+
else:
|
|
297
|
+
template = self.filename_template_linux_amd_64
|
|
298
|
+
candidates = ["filename_template_linux_arm_64", "filename_template_linux_amd_64"]
|
|
299
|
+
elif sys_name == "Darwin":
|
|
300
|
+
if arch == "arm64" and self.filename_template_macos_arm_64:
|
|
301
|
+
template = self.filename_template_macos_arm_64
|
|
302
|
+
elif arch == "amd64" and self.filename_template_macos_amd_64:
|
|
303
|
+
template = self.filename_template_macos_amd_64
|
|
304
|
+
else:
|
|
305
|
+
# fallback between available mac templates
|
|
306
|
+
template = self.filename_template_macos_arm_64 or self.filename_template_macos_amd_64
|
|
307
|
+
candidates = ["filename_template_macos_arm_64", "filename_template_macos_amd_64"]
|
|
308
|
+
else:
|
|
309
|
+
raise NotImplementedError(f"System {sys_name} not supported")
|
|
310
|
+
|
|
311
|
+
if template is None:
|
|
312
|
+
raise ValueError(f"No filename template available for system={sys_name} arch={arch}. Checked {candidates}")
|
|
313
|
+
|
|
314
|
+
return template, arch
|
|
315
|
+
|
|
238
316
|
@staticmethod
|
|
239
317
|
def get_github_release(repo_url: str, version: Optional[str] = None):
|
|
240
|
-
print(f"\n{'='*80}\nš GITHUB RELEASE DETECTION š\n{'='*80}")
|
|
318
|
+
print(f"\n{'=' * 80}\nš GITHUB RELEASE DETECTION š\n{'=' * 80}")
|
|
241
319
|
print(f"š Inspecting releases at: {repo_url}")
|
|
242
320
|
# with console.status("Installing..."): # makes troubles on linux when prompt asks for password to move file to /usr/bin
|
|
243
321
|
if version is None:
|
|
244
322
|
# see this: https://api.github.com/repos/cointop-sh/cointop/releases/latest
|
|
245
323
|
print("š Finding latest version...")
|
|
246
324
|
import requests # https://docs.github.com/en/repositories/releasing-projects-on-github/linking-to-releases
|
|
247
|
-
|
|
325
|
+
|
|
326
|
+
_latest_version = requests.get(str(repo_url) + "/releases/latest", timeout=10).url.split("/")[
|
|
327
|
+
-1
|
|
328
|
+
] # this is to resolve the redirection that occures: https://stackoverflow.com/questions/36070821/how-to-get-redirect-url-using-python-requests
|
|
248
329
|
version_to_be_installed = _latest_version
|
|
249
330
|
print(f"ā
Latest version detected: {version_to_be_installed}")
|
|
250
331
|
# print(version_to_be_installed)
|
|
@@ -253,12 +334,12 @@ class Installer:
|
|
|
253
334
|
print(f"š Using specified version: {version_to_be_installed}")
|
|
254
335
|
|
|
255
336
|
release_url = Path(repo_url + "/releases/download/" + version_to_be_installed)
|
|
256
|
-
print(f"š Release download URL: {release_url}\n{'='*80}")
|
|
337
|
+
print(f"š Release download URL: {release_url}\n{'=' * 80}")
|
|
257
338
|
return release_url, version_to_be_installed
|
|
258
339
|
|
|
259
340
|
@staticmethod
|
|
260
341
|
def check_if_installed_already(exe_name: str, version: str, use_cache: bool):
|
|
261
|
-
print(f"\n{'='*80}\nš CHECKING INSTALLATION STATUS: {exe_name} š\n{'='*80}")
|
|
342
|
+
print(f"\n{'=' * 80}\nš CHECKING INSTALLATION STATUS: {exe_name} š\n{'=' * 80}")
|
|
262
343
|
version_to_be_installed = version
|
|
263
344
|
INSTALL_VERSION_ROOT.joinpath(exe_name).parent.mkdir(parents=True, exist_ok=True)
|
|
264
345
|
tmp_path = INSTALL_VERSION_ROOT.joinpath(exe_name)
|
|
@@ -274,7 +355,7 @@ class Installer:
|
|
|
274
355
|
else:
|
|
275
356
|
print("š Checking installed version directly...")
|
|
276
357
|
result = subprocess.run([exe_name, "--version"], check=False, capture_output=True, text=True)
|
|
277
|
-
if result.stdout.strip() ==
|
|
358
|
+
if result.stdout.strip() == "":
|
|
278
359
|
existing_version = None
|
|
279
360
|
print("ā¹ļø Could not detect installed version")
|
|
280
361
|
else:
|
|
@@ -285,7 +366,7 @@ class Installer:
|
|
|
285
366
|
if existing_version == version_to_be_installed:
|
|
286
367
|
print(f"ā
{exe_name} is up to date (version {version_to_be_installed})")
|
|
287
368
|
print(f"š Version information stored at: {INSTALL_VERSION_ROOT}")
|
|
288
|
-
return ("ā
|
|
369
|
+
return ("ā
Up to date", version.strip(), version_to_be_installed.strip())
|
|
289
370
|
else:
|
|
290
371
|
print(f"š {exe_name} needs update: {existing_version.rstrip()} ā {version_to_be_installed}")
|
|
291
372
|
tmp_path.write_text(version_to_be_installed, encoding="utf-8")
|
|
@@ -294,5 +375,5 @@ class Installer:
|
|
|
294
375
|
print(f"š¦ {exe_name} is not installed. Will install version: {version_to_be_installed}")
|
|
295
376
|
tmp_path.write_text(version_to_be_installed, encoding="utf-8")
|
|
296
377
|
|
|
297
|
-
print(f"{'='*80}")
|
|
378
|
+
print(f"{'=' * 80}")
|
|
298
379
|
return ("ā ļø NotInstalled", "None", version_to_be_installed.strip())
|