machineconfig 2.0__py3-none-any.whl ā 2.1__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 +3 -5
- 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 +26 -10
- machineconfig/jobs/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/linux/msc/cli_agents.sh +16 -0
- machineconfig/jobs/python/check_installations.py +1 -0
- 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/__pycache__/__init__.cpython-313.pyc +0 -0
- 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 +14 -21
- 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_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 +29 -22
- machineconfig/profile/create_hardlinks.py +26 -19
- machineconfig/profile/shell.py +51 -28
- 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 +4 -6
- 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__/croshell.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_jobs.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/__init__.py +0 -0
- machineconfig/scripts/python/ai/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/__pycache__/generate_files.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/__pycache__/mcinit.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/generate_files.py +84 -0
- machineconfig/scripts/python/ai/instructions/python/dev.instructions.md +2 -2
- machineconfig/scripts/python/ai/mcinit.py +7 -3
- machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +10 -5
- machineconfig/scripts/python/cloud_copy.py +1 -1
- machineconfig/scripts/python/cloud_mount.py +1 -1
- machineconfig/scripts/python/cloud_repo_sync.py +4 -4
- machineconfig/scripts/python/croshell.py +5 -3
- machineconfig/scripts/python/devops_add_identity.py +1 -1
- machineconfig/scripts/python/devops_add_ssh_key.py +1 -1
- machineconfig/scripts/python/devops_backup_retrieve.py +1 -1
- machineconfig/scripts/python/devops_update_repos.py +140 -52
- machineconfig/scripts/python/dotfile.py +1 -1
- machineconfig/scripts/python/fire_agents.py +28 -9
- machineconfig/scripts/python/fire_jobs.py +3 -4
- machineconfig/scripts/python/ftpx.py +2 -1
- machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-313.pyc +0 -0
- machineconfig/scripts/python/helpers/helpers2.py +2 -2
- machineconfig/scripts/python/helpers/helpers4.py +1 -2
- machineconfig/scripts/python/helpers/repo_sync_helpers.py +1 -1
- machineconfig/scripts/python/mount_nfs.py +1 -1
- machineconfig/scripts/python/mount_ssh.py +1 -1
- machineconfig/scripts/python/repos.py +1 -1
- machineconfig/scripts/python/start_slidev.py +1 -1
- machineconfig/scripts/python/wsl_windows_transfer.py +1 -1
- 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 +1 -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 +0 -54
- machineconfig/setup_linux/web_shortcuts/interactive.sh +6 -6
- 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 +66 -12
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +44 -36
- 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 +60 -39
- machineconfig/utils/installer.py +27 -33
- machineconfig/utils/installer_utils/installer_abc.py +8 -7
- machineconfig/utils/installer_utils/installer_class.py +149 -70
- machineconfig/utils/links.py +22 -11
- machineconfig/utils/notifications.py +197 -0
- machineconfig/utils/options.py +29 -23
- machineconfig/utils/path.py +13 -6
- machineconfig/utils/path_reduced.py +485 -216
- machineconfig/utils/procs.py +47 -41
- machineconfig/utils/scheduling.py +0 -1
- machineconfig/utils/ssh.py +157 -76
- machineconfig/utils/terminal.py +82 -37
- machineconfig/utils/utils.py +12 -10
- machineconfig/utils/utils2.py +38 -48
- machineconfig/utils/utils5.py +183 -116
- machineconfig/utils/ve.py +9 -4
- {machineconfig-2.0.dist-info ā machineconfig-2.1.dist-info}/METADATA +3 -2
- {machineconfig-2.0.dist-info ā machineconfig-2.1.dist-info}/RECORD +200 -217
- 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__/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__/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__/repo_sync_helpers.cpython-311.pyc +0 -0
- machineconfig/scripts/windows/activate_ve.ps1 +0 -54
- {machineconfig-2.0.dist-info ā machineconfig-2.1.dist-info}/WHEEL +0 -0
- {machineconfig-2.0.dist-info ā machineconfig-2.1.dist-info}/top_level.txt +0 -0
machineconfig/utils/installer.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
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
|
|
8
|
+
from machineconfig.utils.path_reduced import PathExtended as PathExtended
|
|
9
9
|
from machineconfig.utils.utils import INSTALL_VERSION_ROOT
|
|
10
10
|
from machineconfig.utils.utils2 import read_json
|
|
11
11
|
|
|
@@ -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,12 +163,12 @@ 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
174
|
INSTALL_VERSION_ROOT.delete(sure=True)
|
|
@@ -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,4 +1,4 @@
|
|
|
1
|
-
from machineconfig.utils.path_reduced import
|
|
1
|
+
from machineconfig.utils.path_reduced import PathExtended as PathExtended
|
|
2
2
|
from typing import Optional, TypeAlias, Literal
|
|
3
3
|
import subprocess
|
|
4
4
|
|
|
@@ -9,9 +9,10 @@ WINDOWS_INSTALL_PATH = PathExtended.home().joinpath("AppData/Local/Microsoft/Win
|
|
|
9
9
|
CATEGORY: TypeAlias = Literal["OS_SPECIFIC", "OS_GENERIC", "CUSTOM", "OS_SPECIFIC_DEV", "OS_GENERIC_DEV", "CUSTOM_DEV"]
|
|
10
10
|
|
|
11
11
|
|
|
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:
|
|
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:
|
|
15
|
+
exe_name = exe_name.replace(".exe", "")
|
|
15
16
|
if downloaded_file_path.is_file():
|
|
16
17
|
exe = downloaded_file_path
|
|
17
18
|
print(f"š Found direct executable file: {exe}")
|
|
@@ -49,12 +50,12 @@ def find_move_delete_windows(downloaded_file_path: PathExtended, exe_name: Optio
|
|
|
49
50
|
downloaded_file_path.delete(sure=True)
|
|
50
51
|
print("ā
Temporary files removed")
|
|
51
52
|
|
|
52
|
-
print(f"{'='*80}")
|
|
53
|
+
print(f"{'=' * 80}")
|
|
53
54
|
return exe_new_location
|
|
54
55
|
|
|
55
56
|
|
|
56
57
|
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}")
|
|
58
|
+
print(f"\n{'=' * 80}\nš PROCESSING LINUX EXECUTABLE š\n{'=' * 80}")
|
|
58
59
|
if downloaded.is_file():
|
|
59
60
|
exe = downloaded
|
|
60
61
|
print(f"š Found direct executable file: {exe}")
|
|
@@ -108,5 +109,5 @@ def find_move_delete_linux(downloaded: PathExtended, tool_name: str, delete: Opt
|
|
|
108
109
|
print("ā
Temporary files removed")
|
|
109
110
|
|
|
110
111
|
exe_new_location = PathExtended(LINUX_INSTALL_PATH).joinpath(exe.name)
|
|
111
|
-
print(f"ā
Executable installed at: {exe_new_location}\n{'='*80}")
|
|
112
|
+
print(f"ā
Executable installed at: {exe_new_location}\n{'=' * 80}")
|
|
112
113
|
return exe_new_location
|
|
@@ -1,5 +1,4 @@
|
|
|
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
3
|
from machineconfig.utils.utils import INSTALL_TMP_DIR, INSTALL_VERSION_ROOT, LIBRARY_ROOT, check_tool_exists
|
|
5
4
|
from machineconfig.utils.utils2 import pprint, read_json
|
|
@@ -11,45 +10,59 @@ from pathlib import Path
|
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
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
|
-
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
repo_url: str,
|
|
16
|
+
name: str,
|
|
17
|
+
doc: str,
|
|
18
|
+
strip_v: bool,
|
|
19
|
+
exe_name: str,
|
|
20
|
+
filename_template_windows_amd_64: str,
|
|
21
|
+
filename_template_linux_amd_64: str,
|
|
22
|
+
filename_template_windows_arm_64: Optional[str] = None,
|
|
23
|
+
filename_template_linux_arm_64: Optional[str] = None,
|
|
24
|
+
filename_template_macos_amd_64: Optional[str] = None,
|
|
25
|
+
filename_template_macos_arm_64: Optional[str] = None,
|
|
26
|
+
):
|
|
27
|
+
self.repo_url: str = repo_url
|
|
28
|
+
self.name: str = name
|
|
29
|
+
self.doc: str = doc
|
|
30
|
+
self.filename_template_windows_amd_64: str = filename_template_windows_amd_64
|
|
31
|
+
self.filename_template_windows_arm_64: Optional[str] = filename_template_windows_arm_64
|
|
32
|
+
self.filename_template_linux_arm_64: Optional[str] = filename_template_linux_arm_64
|
|
33
|
+
self.filename_template_linux_amd_64: str = filename_template_linux_amd_64
|
|
34
|
+
self.filename_template_macos_amd_64: Optional[str] = filename_template_macos_amd_64
|
|
35
|
+
self.filename_template_macos_arm_64: Optional[str] = filename_template_macos_arm_64
|
|
36
|
+
self.strip_v: bool = strip_v
|
|
37
|
+
self.exe_name: str = exe_name
|
|
38
|
+
|
|
39
|
+
def __repr__(self) -> str:
|
|
40
|
+
return f"Installer of {self.exe_name} {self.name} @ {self.repo_url}"
|
|
41
|
+
|
|
35
42
|
def get_description(self):
|
|
36
43
|
# old_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
|
|
37
44
|
# 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)
|
|
45
|
+
old_version_cli: bool = check_tool_exists(tool_name=self.exe_name)
|
|
39
46
|
old_version_cli_str = "ā
" if old_version_cli else "ā"
|
|
40
47
|
# name_version = f"{self.exe_name} {old_version_cli_str}"
|
|
41
48
|
return f"{self.exe_name:<12} {old_version_cli_str} {self.doc}"
|
|
42
|
-
|
|
49
|
+
|
|
50
|
+
def to_dict(self):
|
|
51
|
+
return self.__dict__
|
|
52
|
+
|
|
43
53
|
@staticmethod
|
|
44
54
|
def from_dict(d: dict[str, Any], name: str):
|
|
45
|
-
try:
|
|
55
|
+
try:
|
|
56
|
+
return Installer(name=name, **d)
|
|
46
57
|
except Exception as ex:
|
|
47
58
|
pprint(d, "Installer Creation Error")
|
|
48
59
|
raise ex
|
|
60
|
+
|
|
49
61
|
@staticmethod
|
|
50
62
|
def choose_app_and_install():
|
|
51
|
-
print(f"\n{'='*80}\nš SELECT APPLICATION TO INSTALL š\n{'='*80}")
|
|
63
|
+
print(f"\n{'=' * 80}\nš SELECT APPLICATION TO INSTALL š\n{'=' * 80}")
|
|
52
64
|
from machineconfig.utils.utils import choose_one_option
|
|
65
|
+
|
|
53
66
|
print("š Searching for configuration files...")
|
|
54
67
|
jobs_dir = Path(LIBRARY_ROOT.joinpath("jobs"))
|
|
55
68
|
config_paths = [Path(p) for p in jobs_dir.rglob("config.json")]
|
|
@@ -62,12 +75,12 @@ class Installer:
|
|
|
62
75
|
installer = Installer.from_dict(d=config[app_name], name=app_name)
|
|
63
76
|
print(f"š¦ Selected application: {installer.exe_name}")
|
|
64
77
|
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}")
|
|
78
|
+
print(f"\n{'=' * 80}\nš INSTALLING {installer.exe_name.upper()} š\n{'=' * 80}")
|
|
66
79
|
installer.install(version=version)
|
|
67
80
|
|
|
68
81
|
def install_robust(self, version: Optional[str]):
|
|
69
82
|
try:
|
|
70
|
-
print(f"\n{'='*80}\nš INSTALLING {self.exe_name.upper()} š\n{'='*80}")
|
|
83
|
+
print(f"\n{'=' * 80}\nš INSTALLING {self.exe_name.upper()} š\n{'=' * 80}")
|
|
71
84
|
result_old = subprocess.run(f"{self.exe_name} --version", shell=True, capture_output=True, text=True)
|
|
72
85
|
old_version_cli = result_old.stdout.strip()
|
|
73
86
|
print(f"š Current version: {old_version_cli or 'Not installed'}")
|
|
@@ -90,10 +103,11 @@ class Installer:
|
|
|
90
103
|
return f"""echo "š¦ļø ā Failed to install `{self.name}` with error: {ex}" """
|
|
91
104
|
|
|
92
105
|
def install(self, version: Optional[str]):
|
|
93
|
-
print(f"\n{'='*80}\nš§ INSTALLATION PROCESS: {self.exe_name} š§\n{'='*80}")
|
|
106
|
+
print(f"\n{'=' * 80}\nš§ INSTALLATION PROCESS: {self.exe_name} š§\n{'=' * 80}")
|
|
94
107
|
if self.repo_url == "CUSTOM":
|
|
95
108
|
print(f"š§© Using custom installer for {self.exe_name}")
|
|
96
109
|
import machineconfig.jobs.python_custom_installers as python_custom_installers
|
|
110
|
+
|
|
97
111
|
installer_path = Path(python_custom_installers.__file__).parent.joinpath(self.exe_name + ".py")
|
|
98
112
|
if not installer_path.exists():
|
|
99
113
|
installer_path = Path(python_custom_installers.__file__).parent.joinpath("dev", self.exe_name + ".py")
|
|
@@ -102,12 +116,15 @@ class Installer:
|
|
|
102
116
|
print(f"š Found installer at: {installer_path}")
|
|
103
117
|
|
|
104
118
|
import runpy
|
|
119
|
+
|
|
105
120
|
print(f"āļø Executing function 'main' from '{installer_path}'...")
|
|
106
|
-
program: str = runpy.run_path(str(installer_path), run_name=None)[
|
|
121
|
+
program: str = runpy.run_path(str(installer_path), run_name=None)["main"](version=version)
|
|
107
122
|
# print(program)
|
|
108
123
|
print("š Running installation script...")
|
|
109
|
-
if platform.system() == "Linux":
|
|
110
|
-
|
|
124
|
+
if platform.system() == "Linux":
|
|
125
|
+
script = "#!/bin/bash" + "\n" + program
|
|
126
|
+
else:
|
|
127
|
+
script = program
|
|
111
128
|
script_file = PathExtended.tmpfile(name="tmp_shell_script", suffix=".ps1" if platform.system() == "Windows" else ".sh", folder="tmp_scripts").write_text(script, newline=None if platform.system() == "Windows" else "\n")
|
|
112
129
|
if platform.system() == "Windows":
|
|
113
130
|
start_cmd = "powershell"
|
|
@@ -117,7 +134,7 @@ class Installer:
|
|
|
117
134
|
full_command = f"{start_cmd} {script_file}"
|
|
118
135
|
subprocess.run(full_command, stdin=None, stdout=None, stderr=None, shell=True, text=True)
|
|
119
136
|
version_to_be_installed = str(version)
|
|
120
|
-
print(f"ā
Custom installation completed\n{'='*80}")
|
|
137
|
+
print(f"ā
Custom installation completed\n{'=' * 80}")
|
|
121
138
|
|
|
122
139
|
elif "npm " in self.repo_url or "pip " in self.repo_url or "winget " in self.repo_url:
|
|
123
140
|
package_manager = self.repo_url.split(" ", maxsplit=1)[0]
|
|
@@ -134,7 +151,7 @@ class Installer:
|
|
|
134
151
|
if result.stderr:
|
|
135
152
|
print(f"STDERR: {result.stderr}")
|
|
136
153
|
print(f"Return code: {result.returncode}")
|
|
137
|
-
print(f"ā
Package manager installation completed\n{'='*80}")
|
|
154
|
+
print(f"ā
Package manager installation completed\n{'=' * 80}")
|
|
138
155
|
|
|
139
156
|
else:
|
|
140
157
|
print("š„ Downloading from repository...")
|
|
@@ -154,7 +171,7 @@ class Installer:
|
|
|
154
171
|
print(f"Return code: {result.returncode}")
|
|
155
172
|
print("šļø Cleaning up .deb package...")
|
|
156
173
|
downloaded.delete(sure=True)
|
|
157
|
-
print(f"ā
DEB package installation completed\n{'='*80}")
|
|
174
|
+
print(f"ā
DEB package installation completed\n{'=' * 80}")
|
|
158
175
|
else:
|
|
159
176
|
if platform.system() == "Windows":
|
|
160
177
|
print("šŖ Installing on Windows...")
|
|
@@ -172,6 +189,7 @@ class Installer:
|
|
|
172
189
|
if exe.name.replace(".exe", "") != self.exe_name.replace(".exe", ""):
|
|
173
190
|
from rich import print as pprint
|
|
174
191
|
from rich.panel import Panel
|
|
192
|
+
|
|
175
193
|
print("ā ļø Warning: Executable name mismatch")
|
|
176
194
|
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
195
|
new_exe_name = self.exe_name + ".exe" if platform.system() == "Windows" else self.exe_name
|
|
@@ -181,30 +199,30 @@ class Installer:
|
|
|
181
199
|
print(f"š¾ Saving version information to: {INSTALL_VERSION_ROOT.joinpath(self.exe_name)}")
|
|
182
200
|
INSTALL_VERSION_ROOT.joinpath(self.exe_name).parent.mkdir(parents=True, exist_ok=True)
|
|
183
201
|
INSTALL_VERSION_ROOT.joinpath(self.exe_name).write_text(version_to_be_installed, encoding="utf-8")
|
|
184
|
-
print(f"ā
Installation completed successfully!\n{'='*80}")
|
|
202
|
+
print(f"ā
Installation completed successfully!\n{'=' * 80}")
|
|
185
203
|
|
|
186
204
|
def download(self, version: Optional[str]):
|
|
187
|
-
print(f"\n{'='*80}\nš„ DOWNLOADING: {self.exe_name} š„\n{'='*80}")
|
|
205
|
+
print(f"\n{'=' * 80}\nš„ DOWNLOADING: {self.exe_name} š„\n{'=' * 80}")
|
|
206
|
+
download_link: Optional[Path] = None
|
|
207
|
+
version_to_be_installed: Optional[str] = None
|
|
188
208
|
if "github" not in self.repo_url or ".zip" in self.repo_url or ".tar.gz" in self.repo_url:
|
|
189
209
|
download_link = Path(self.repo_url)
|
|
190
210
|
version_to_be_installed = "predefined_url"
|
|
191
211
|
print(f"š Using direct download URL: {download_link}")
|
|
192
212
|
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}")
|
|
213
|
+
elif self._any_direct_http_template():
|
|
214
|
+
template, arch = self._select_template()
|
|
215
|
+
if not template.startswith("http"):
|
|
216
|
+
# Fall back to github-style handling below
|
|
217
|
+
pass
|
|
202
218
|
else:
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
219
|
+
download_link = Path(template)
|
|
220
|
+
version_to_be_installed = "predefined_url"
|
|
221
|
+
system_name = self._system_name()
|
|
222
|
+
print(f"š§ Detected system={system_name} arch={arch}")
|
|
223
|
+
print(f"š Using architecture-specific direct URL: {download_link}")
|
|
224
|
+
print(f"š¦ Version to be installed: {version_to_be_installed}")
|
|
225
|
+
# continue to unified download logic below
|
|
208
226
|
|
|
209
227
|
else:
|
|
210
228
|
print("š Retrieving release information from GitHub...")
|
|
@@ -215,36 +233,97 @@ class Installer:
|
|
|
215
233
|
version_to_be_installed_stripped = version_to_be_installed.replace("v", "") if self.strip_v else version_to_be_installed
|
|
216
234
|
version_to_be_installed_stripped = version_to_be_installed_stripped.replace("ipinfo-", "")
|
|
217
235
|
|
|
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)
|
|
236
|
+
template, arch = self._select_template()
|
|
237
|
+
system_name = self._system_name()
|
|
238
|
+
file_name = template.format(version_to_be_installed_stripped)
|
|
239
|
+
print(f"š§ Detected system={system_name} arch={arch}")
|
|
240
|
+
print(f"š Using template: {template}")
|
|
241
|
+
print(f"šļø Resolved file name: {file_name}")
|
|
229
242
|
|
|
230
243
|
print(f"š File name: {file_name}")
|
|
231
244
|
download_link = release_url.joinpath(file_name)
|
|
232
245
|
|
|
246
|
+
assert download_link is not None, "download_link must be set"
|
|
247
|
+
assert version_to_be_installed is not None, "version_to_be_installed must be set"
|
|
233
248
|
print(f"š„ Downloading {self.name} from: {download_link}")
|
|
234
249
|
downloaded = PathExtended(download_link).download(folder=INSTALL_TMP_DIR).decompress()
|
|
235
|
-
print(f"ā
Download and extraction completed to: {downloaded}\n{'='*80}")
|
|
250
|
+
print(f"ā
Download and extraction completed to: {downloaded}\n{'=' * 80}")
|
|
236
251
|
return downloaded, version_to_be_installed
|
|
237
252
|
|
|
253
|
+
# --------------------------- Arch / template helpers ---------------------------
|
|
254
|
+
def _normalized_arch(self) -> str:
|
|
255
|
+
arch_raw = platform.machine().lower()
|
|
256
|
+
if arch_raw in ("x86_64", "amd64"):
|
|
257
|
+
return "amd64"
|
|
258
|
+
if arch_raw in ("aarch64", "arm64", "armv8", "armv8l"):
|
|
259
|
+
return "arm64"
|
|
260
|
+
return arch_raw
|
|
261
|
+
|
|
262
|
+
def _system_name(self) -> str:
|
|
263
|
+
sys_ = platform.system()
|
|
264
|
+
if sys_ == "Darwin":
|
|
265
|
+
return "macOS"
|
|
266
|
+
return sys_
|
|
267
|
+
|
|
268
|
+
def _any_direct_http_template(self) -> bool:
|
|
269
|
+
templates: list[Optional[str]] = [
|
|
270
|
+
self.filename_template_windows_amd_64,
|
|
271
|
+
self.filename_template_windows_arm_64,
|
|
272
|
+
self.filename_template_linux_amd_64,
|
|
273
|
+
self.filename_template_linux_arm_64,
|
|
274
|
+
self.filename_template_macos_amd_64,
|
|
275
|
+
self.filename_template_macos_arm_64,
|
|
276
|
+
]
|
|
277
|
+
return any(t for t in templates if t is not None and t.startswith("http"))
|
|
278
|
+
|
|
279
|
+
def _select_template(self) -> tuple[str, str]:
|
|
280
|
+
sys_name = platform.system()
|
|
281
|
+
arch = self._normalized_arch()
|
|
282
|
+
# mapping logic
|
|
283
|
+
candidates: list[str] = []
|
|
284
|
+
template: Optional[str] = None
|
|
285
|
+
if sys_name == "Windows":
|
|
286
|
+
if arch == "arm64" and self.filename_template_windows_arm_64:
|
|
287
|
+
template = self.filename_template_windows_arm_64
|
|
288
|
+
else:
|
|
289
|
+
template = self.filename_template_windows_amd_64
|
|
290
|
+
candidates = ["filename_template_windows_arm_64", "filename_template_windows_amd_64"]
|
|
291
|
+
elif sys_name == "Linux":
|
|
292
|
+
if arch == "arm64" and self.filename_template_linux_arm_64:
|
|
293
|
+
template = self.filename_template_linux_arm_64
|
|
294
|
+
else:
|
|
295
|
+
template = self.filename_template_linux_amd_64
|
|
296
|
+
candidates = ["filename_template_linux_arm_64", "filename_template_linux_amd_64"]
|
|
297
|
+
elif sys_name == "Darwin":
|
|
298
|
+
if arch == "arm64" and self.filename_template_macos_arm_64:
|
|
299
|
+
template = self.filename_template_macos_arm_64
|
|
300
|
+
elif arch == "amd64" and self.filename_template_macos_amd_64:
|
|
301
|
+
template = self.filename_template_macos_amd_64
|
|
302
|
+
else:
|
|
303
|
+
# fallback between available mac templates
|
|
304
|
+
template = self.filename_template_macos_arm_64 or self.filename_template_macos_amd_64
|
|
305
|
+
candidates = ["filename_template_macos_arm_64", "filename_template_macos_amd_64"]
|
|
306
|
+
else:
|
|
307
|
+
raise NotImplementedError(f"System {sys_name} not supported")
|
|
308
|
+
|
|
309
|
+
if template is None:
|
|
310
|
+
raise ValueError(f"No filename template available for system={sys_name} arch={arch}. Checked {candidates}")
|
|
311
|
+
|
|
312
|
+
return template, arch
|
|
313
|
+
|
|
238
314
|
@staticmethod
|
|
239
315
|
def get_github_release(repo_url: str, version: Optional[str] = None):
|
|
240
|
-
print(f"\n{'='*80}\nš GITHUB RELEASE DETECTION š\n{'='*80}")
|
|
316
|
+
print(f"\n{'=' * 80}\nš GITHUB RELEASE DETECTION š\n{'=' * 80}")
|
|
241
317
|
print(f"š Inspecting releases at: {repo_url}")
|
|
242
318
|
# with console.status("Installing..."): # makes troubles on linux when prompt asks for password to move file to /usr/bin
|
|
243
319
|
if version is None:
|
|
244
320
|
# see this: https://api.github.com/repos/cointop-sh/cointop/releases/latest
|
|
245
321
|
print("š Finding latest version...")
|
|
246
322
|
import requests # https://docs.github.com/en/repositories/releasing-projects-on-github/linking-to-releases
|
|
247
|
-
|
|
323
|
+
|
|
324
|
+
_latest_version = requests.get(str(repo_url) + "/releases/latest", timeout=10).url.split("/")[
|
|
325
|
+
-1
|
|
326
|
+
] # this is to resolve the redirection that occures: https://stackoverflow.com/questions/36070821/how-to-get-redirect-url-using-python-requests
|
|
248
327
|
version_to_be_installed = _latest_version
|
|
249
328
|
print(f"ā
Latest version detected: {version_to_be_installed}")
|
|
250
329
|
# print(version_to_be_installed)
|
|
@@ -253,12 +332,12 @@ class Installer:
|
|
|
253
332
|
print(f"š Using specified version: {version_to_be_installed}")
|
|
254
333
|
|
|
255
334
|
release_url = Path(repo_url + "/releases/download/" + version_to_be_installed)
|
|
256
|
-
print(f"š Release download URL: {release_url}\n{'='*80}")
|
|
335
|
+
print(f"š Release download URL: {release_url}\n{'=' * 80}")
|
|
257
336
|
return release_url, version_to_be_installed
|
|
258
337
|
|
|
259
338
|
@staticmethod
|
|
260
339
|
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}")
|
|
340
|
+
print(f"\n{'=' * 80}\nš CHECKING INSTALLATION STATUS: {exe_name} š\n{'=' * 80}")
|
|
262
341
|
version_to_be_installed = version
|
|
263
342
|
INSTALL_VERSION_ROOT.joinpath(exe_name).parent.mkdir(parents=True, exist_ok=True)
|
|
264
343
|
tmp_path = INSTALL_VERSION_ROOT.joinpath(exe_name)
|
|
@@ -274,7 +353,7 @@ class Installer:
|
|
|
274
353
|
else:
|
|
275
354
|
print("š Checking installed version directly...")
|
|
276
355
|
result = subprocess.run([exe_name, "--version"], check=False, capture_output=True, text=True)
|
|
277
|
-
if result.stdout.strip() ==
|
|
356
|
+
if result.stdout.strip() == "":
|
|
278
357
|
existing_version = None
|
|
279
358
|
print("ā¹ļø Could not detect installed version")
|
|
280
359
|
else:
|
|
@@ -294,5 +373,5 @@ class Installer:
|
|
|
294
373
|
print(f"š¦ {exe_name} is not installed. Will install version: {version_to_be_installed}")
|
|
295
374
|
tmp_path.write_text(version_to_be_installed, encoding="utf-8")
|
|
296
375
|
|
|
297
|
-
print(f"{'='*80}")
|
|
376
|
+
print(f"{'=' * 80}")
|
|
298
377
|
return ("ā ļø NotInstalled", "None", version_to_be_installed.strip())
|