machineconfig 1.7__py3-none-any.whl → 1.9__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/__init__.py +4 -2
- machineconfig/jobs/python/check_installations.py +38 -32
- machineconfig/jobs/python/create_bootable_media.py +4 -4
- machineconfig/jobs/python/create_zellij_template.py +3 -2
- machineconfig/jobs/python/python_cargo_build_share.py +14 -9
- machineconfig/jobs/python/python_ve_symlink.py +6 -6
- machineconfig/jobs/python_custom_installers/azuredatastudio.py +36 -0
- machineconfig/jobs/python_custom_installers/bypass_paywall.py +30 -0
- machineconfig/jobs/{python_linux_installers/dev → python_custom_installers}/docker_desktop.py +15 -4
- machineconfig/jobs/python_custom_installers/gh.py +53 -0
- machineconfig/jobs/python_custom_installers/goes.py +35 -0
- machineconfig/jobs/python_custom_installers/helix.py +43 -0
- machineconfig/jobs/python_custom_installers/lvim.py +48 -0
- machineconfig/jobs/python_custom_installers/ngrok.py +39 -0
- machineconfig/jobs/python_custom_installers/nvim.py +48 -0
- machineconfig/jobs/python_custom_installers/vscode.py +45 -0
- machineconfig/jobs/python_custom_installers/wezterm.py +41 -0
- machineconfig/profile/create.py +12 -7
- machineconfig/profile/shell.py +15 -13
- machineconfig/scripts/python/choose_wezterm_theme.py +96 -0
- machineconfig/scripts/python/cloud_copy.py +18 -13
- machineconfig/scripts/python/cloud_mount.py +41 -15
- machineconfig/scripts/python/cloud_repo_sync.py +57 -31
- machineconfig/scripts/python/cloud_sync.py +13 -15
- machineconfig/scripts/python/croshell.py +19 -10
- machineconfig/scripts/python/devops.py +22 -6
- machineconfig/scripts/python/devops_add_identity.py +7 -6
- machineconfig/scripts/python/devops_add_ssh_key.py +10 -9
- machineconfig/scripts/python/devops_backup_retrieve.py +5 -5
- machineconfig/scripts/python/devops_devapps_install.py +24 -19
- machineconfig/scripts/python/devops_update_repos.py +5 -4
- machineconfig/scripts/python/dotfile.py +8 -4
- machineconfig/scripts/python/fire_jobs.py +165 -55
- machineconfig/scripts/python/ftpx.py +18 -8
- machineconfig/scripts/python/mount_nfs.py +13 -10
- machineconfig/scripts/python/mount_nw_drive.py +4 -3
- machineconfig/scripts/python/mount_ssh.py +8 -5
- machineconfig/scripts/python/repos.py +26 -21
- machineconfig/scripts/python/snapshot.py +2 -2
- machineconfig/scripts/python/start_slidev.py +104 -0
- machineconfig/scripts/python/start_terminals.py +1 -1
- machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +20 -34
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +11 -12
- machineconfig/utils/installer.py +177 -217
- machineconfig/utils/scheduling.py +1 -1
- machineconfig/utils/utils.py +107 -54
- machineconfig/utils/ve.py +120 -16
- machineconfig-1.9.dist-info/LICENSE +201 -0
- {machineconfig-1.7.dist-info → machineconfig-1.9.dist-info}/METADATA +155 -140
- machineconfig-1.9.dist-info/RECORD +76 -0
- {machineconfig-1.7.dist-info → machineconfig-1.9.dist-info}/WHEEL +1 -1
- machineconfig/jobs/python_generic_installers/archive/gopass.py +0 -18
- machineconfig/jobs/python_generic_installers/archive/nvim.py +0 -20
- machineconfig/jobs/python_generic_installers/archive/opencommit.py +0 -25
- machineconfig/jobs/python_generic_installers/archive/strongbox.py +0 -33
- machineconfig/jobs/python_generic_installers/dev/__init__.py +0 -0
- machineconfig/jobs/python_linux_installers/archive/__init__.py +0 -0
- machineconfig/jobs/python_linux_installers/archive/bandwhich.py +0 -14
- machineconfig/jobs/python_linux_installers/archive/ranger.py +0 -19
- machineconfig/jobs/python_linux_installers/dev/azure_data_studio.py +0 -21
- machineconfig/jobs/python_linux_installers/dev/bytehound.py +0 -20
- machineconfig/jobs/python_linux_installers/dev/nnn.py +0 -22
- machineconfig/jobs/python_windows_installers/archive/ntop.py +0 -21
- machineconfig/jobs/python_windows_installers/dev/bypass_paywall.py +0 -22
- machineconfig/jobs/python_windows_installers/dev/obs_background_removal_plugin.py +0 -22
- machineconfig/scripts/python/choose_ohmybash_theme.py +0 -31
- machineconfig/scripts/python/choose_ohmyposh_theme.py +0 -57
- machineconfig/utils/pandas_type.py +0 -37
- machineconfig/utils/to_exe.py +0 -7
- machineconfig-1.7.dist-info/RECORD +0 -81
- /machineconfig/jobs/{python_generic_installers/archive → python_custom_installers}/__init__.py +0 -0
- {machineconfig-1.7.dist-info → machineconfig-1.9.dist-info}/top_level.txt +0 -0
machineconfig/utils/installer.py
CHANGED
|
@@ -5,14 +5,20 @@ from rich.console import Console
|
|
|
5
5
|
|
|
6
6
|
from crocodile.file_management import P, List as L, Read, Struct
|
|
7
7
|
from crocodile.meta import Terminal
|
|
8
|
-
from machineconfig.utils.utils import INSTALL_VERSION_ROOT, INSTALL_TMP_DIR, LIBRARY_ROOT
|
|
8
|
+
from machineconfig.utils.utils import INSTALL_VERSION_ROOT, INSTALL_TMP_DIR, LIBRARY_ROOT, check_tool_exists
|
|
9
9
|
|
|
10
|
-
from dataclasses import dataclass
|
|
10
|
+
# from dataclasses import dataclass
|
|
11
11
|
from typing import Optional, Any
|
|
12
12
|
import platform
|
|
13
|
+
# import os
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
LINUX_INSTALL_PATH = '/usr/local/bin'
|
|
17
|
+
WINDOWS_INSTALL_PATH = '~/AppData/Local/Microsoft/WindowsApps'
|
|
13
18
|
|
|
14
19
|
|
|
15
20
|
def find_move_delete_windows(downloaded_file_path: P, exe_name: Optional[str] = None, delete: bool = True, rename_to: Optional[str] = None):
|
|
21
|
+
"""Moves executable to {WINDOWS_INSTALL_PATH}"""
|
|
16
22
|
if exe_name is not None and ".exe" in exe_name: exe_name = exe_name.replace(".exe", "")
|
|
17
23
|
if downloaded_file_path.is_file():
|
|
18
24
|
exe = downloaded_file_path
|
|
@@ -21,12 +27,16 @@ def find_move_delete_windows(downloaded_file_path: P, exe_name: Optional[str] =
|
|
|
21
27
|
else:
|
|
22
28
|
tmp = downloaded_file_path.search(f"{exe_name}.exe", r=True)
|
|
23
29
|
if len(tmp) == 1: exe = tmp.list[0]
|
|
24
|
-
else:
|
|
30
|
+
else:
|
|
31
|
+
search_res = downloaded_file_path.search("*.exe", r=True)
|
|
32
|
+
if len(search_res) == 0: raise IndexError(f"No executable found in {downloaded_file_path}")
|
|
33
|
+
elif len(search_res) == 1: exe = search_res.list[0]
|
|
34
|
+
else: exe = search_res.sort(lambda x: x.size("kb")).list[-1]
|
|
25
35
|
if rename_to and exe.name != rename_to:
|
|
26
36
|
exe = exe.with_name(name=rename_to, inplace=True)
|
|
27
|
-
exe.move(folder=
|
|
37
|
+
exe_new_location = exe.move(folder=WINDOWS_INSTALL_PATH, overwrite=True) # latest version overwrites older installation.
|
|
28
38
|
if delete: downloaded_file_path.delete(sure=True)
|
|
29
|
-
return
|
|
39
|
+
return exe_new_location
|
|
30
40
|
|
|
31
41
|
|
|
32
42
|
def find_move_delete_linux(downloaded: P, tool_name: str, delete: Optional[bool] = True, rename_to: Optional[str] = None):
|
|
@@ -35,301 +45,247 @@ def find_move_delete_linux(downloaded: P, tool_name: str, delete: Optional[bool]
|
|
|
35
45
|
else:
|
|
36
46
|
res = downloaded.search(f"*{tool_name}*", folders=False, r=True)
|
|
37
47
|
if len(res) == 1: exe = res.list[0]
|
|
38
|
-
else:
|
|
48
|
+
else:
|
|
49
|
+
exe_search_res = downloaded.search(tool_name, folders=False, r=True)
|
|
50
|
+
if len(exe_search_res) == 0:
|
|
51
|
+
print(f"No search results for `{tool_name}` in `{downloaded}`")
|
|
52
|
+
raise IndexError(f"No executable found in {downloaded}")
|
|
53
|
+
elif len(exe_search_res) == 1:
|
|
54
|
+
exe = exe_search_res.list[0]
|
|
55
|
+
else:
|
|
56
|
+
exe = exe_search_res.sort(lambda x: x.size("kb")).list[-1]
|
|
39
57
|
if rename_to and exe.name != rename_to:
|
|
40
58
|
exe = exe.with_name(name=rename_to, inplace=True)
|
|
41
|
-
print(f"MOVING file `{repr(exe)}` to '
|
|
59
|
+
print(f"MOVING file `{repr(exe)}` to '{LINUX_INSTALL_PATH}'")
|
|
42
60
|
exe.chmod(0o777)
|
|
43
|
-
# exe.move(folder=
|
|
44
|
-
Terminal().run(f"sudo mv {exe} /
|
|
61
|
+
# exe.move(folder=LINUX_INSTALL_PATH, overwrite=False)
|
|
62
|
+
Terminal().run(f"sudo mv {exe} {LINUX_INSTALL_PATH}/").print_if_unsuccessful(desc=f"MOVING executable `{exe}` to {LINUX_INSTALL_PATH}", strict_err=True, strict_returncode=True)
|
|
45
63
|
if delete: downloaded.delete(sure=True)
|
|
46
|
-
|
|
64
|
+
exe_new_location = P(LINUX_INSTALL_PATH).joinpath(exe.name)
|
|
65
|
+
return exe_new_location
|
|
47
66
|
|
|
48
67
|
|
|
49
68
|
class Installer:
|
|
50
|
-
def __init__(self, repo_url: str, doc: str, filename_template_windows_amd_64: str, filename_template_linux_amd_64: str, strip_v: bool, exe_name: str):
|
|
69
|
+
def __init__(self, repo_url: str, name: str, doc: str, filename_template_windows_amd_64: str, filename_template_linux_amd_64: str, strip_v: bool, exe_name: str):
|
|
51
70
|
self.repo_url = repo_url
|
|
71
|
+
self.name = name
|
|
52
72
|
self.doc = doc
|
|
53
73
|
self.filename_template_windows_amd_64 = filename_template_windows_amd_64
|
|
54
74
|
self.filename_template_linux_amd_64 = filename_template_linux_amd_64
|
|
55
75
|
self.strip_v = strip_v
|
|
56
76
|
self.exe_name = exe_name
|
|
57
77
|
def __repr__(self) -> str: return f"Installer of {self.repo_url}"
|
|
58
|
-
def get_description(self):
|
|
78
|
+
def get_description(self):
|
|
79
|
+
# old_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
|
|
80
|
+
# old_version_cli = os.system(f"{self.exe_name} --version").replace("\n", "")
|
|
81
|
+
old_version_cli = check_tool_exists(tool_name=self.exe_name)
|
|
82
|
+
old_version_cli_str = "✅" if old_version_cli else "❌"
|
|
83
|
+
# name_version = f"{self.exe_name} {old_version_cli_str}"
|
|
84
|
+
return f"{self.exe_name:<12} {old_version_cli_str} {self.doc}"
|
|
59
85
|
def to_dict(self): return self.__dict__
|
|
60
86
|
@staticmethod
|
|
61
|
-
def from_dict(d: dict[str, Any]):
|
|
62
|
-
try: return Installer(**d)
|
|
87
|
+
def from_dict(d: dict[str, Any], name: str):
|
|
88
|
+
try: return Installer(name=name, **d)
|
|
63
89
|
except Exception as ex:
|
|
64
90
|
Struct(d).print(as_config=True)
|
|
65
91
|
raise ex
|
|
66
92
|
@staticmethod
|
|
67
|
-
def
|
|
93
|
+
def choose_app_and_install():
|
|
68
94
|
from machineconfig.utils.utils import choose_one_option
|
|
69
95
|
path = choose_one_option(options=LIBRARY_ROOT.joinpath("jobs").search("config.json", r=True).list)
|
|
70
96
|
config: dict[str, Any] = Read.json(path) # /python_generic_installers/config.json"))
|
|
71
|
-
|
|
72
|
-
for
|
|
73
|
-
|
|
74
|
-
|
|
97
|
+
app_name = choose_one_option(options=list(config.keys()), fzf=True)
|
|
98
|
+
# for keys, dict_ in config.items():
|
|
99
|
+
installer = Installer.from_dict(d=config[app_name], name=app_name)
|
|
100
|
+
version = input(f"Enter version to install for {installer.exe_name} [latest]: ") or None
|
|
101
|
+
installer.install(version=version)
|
|
75
102
|
|
|
76
103
|
def install_robust(self, version: Optional[str]):
|
|
77
104
|
try:
|
|
78
|
-
|
|
105
|
+
old_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
|
|
79
106
|
self.install(version=version)
|
|
80
|
-
|
|
81
|
-
if
|
|
82
|
-
else: return f"🤩 {self.exe_name} updated from {
|
|
107
|
+
new_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
|
|
108
|
+
if old_version_cli == new_version_cli: return f"📦️ 😑 {self.exe_name}, same version: {old_version_cli}"
|
|
109
|
+
else: return f"📦️ 🤩 {self.exe_name} updated from {old_version_cli} === to ===> {new_version_cli}"
|
|
83
110
|
except Exception as ex:
|
|
84
111
|
print(ex)
|
|
85
|
-
return f"Failed at {self.exe_name} with {ex}"
|
|
86
|
-
|
|
112
|
+
return f"📦️ Failed at {self.exe_name} with {ex}"
|
|
87
113
|
|
|
88
114
|
def install(self, version: Optional[str]):
|
|
115
|
+
if self.repo_url == "CUSTOM":
|
|
116
|
+
import machineconfig.jobs.python_custom_installers as python_custom_installers
|
|
117
|
+
installer_path = P(python_custom_installers.__file__).parent.joinpath(self.exe_name + ".py")
|
|
118
|
+
import runpy
|
|
119
|
+
program = runpy.run_path(str(installer_path), run_name=None)['main'](version=version)
|
|
120
|
+
Terminal().run_script(script=program, shell="default").print(desc="Running custom installer", capture=True)
|
|
121
|
+
# import subprocess
|
|
122
|
+
# subprocess.run(program, shell=True, check=True)
|
|
123
|
+
version_to_be_installed = str(version)
|
|
124
|
+
elif "npm " in self.repo_url:
|
|
125
|
+
Terminal().run(self.repo_url, shell="default").print_if_unsuccessful(desc="npm install", strict_err=True, strict_returncode=True)
|
|
126
|
+
version_to_be_installed = "npmLatest"
|
|
127
|
+
elif "pip " in self.repo_url:
|
|
128
|
+
Terminal().run(self.repo_url, shell="default").print_if_unsuccessful(desc="pip install", strict_err=True, strict_returncode=True)
|
|
129
|
+
version_to_be_installed = "pipLatest"
|
|
130
|
+
else:
|
|
131
|
+
downloaded, version_to_be_installed = self.download(version=version)
|
|
132
|
+
if downloaded.str.endswith(".deb"):
|
|
133
|
+
assert platform.system() == "Linux"
|
|
134
|
+
Terminal().run(f"sudo apt install -y {downloaded}").print_if_unsuccessful(desc="Installing .deb", strict_err=True, strict_returncode=True)
|
|
135
|
+
downloaded.delete(sure=True)
|
|
136
|
+
else:
|
|
137
|
+
if platform.system() == "Windows":
|
|
138
|
+
exe = find_move_delete_windows(downloaded_file_path=downloaded, exe_name=self.exe_name, delete=True, rename_to=self.exe_name + ".exe")
|
|
139
|
+
elif platform.system() == "Linux":
|
|
140
|
+
exe = find_move_delete_linux(downloaded=downloaded, tool_name=self.exe_name, delete=True, rename_to=self.exe_name)
|
|
141
|
+
else: raise NotImplementedError(f"System {platform.system()} not implemented")
|
|
142
|
+
_ = exe
|
|
143
|
+
if exe.name.replace(".exe", "") != self.exe_name.replace(".exe", ""):
|
|
144
|
+
from rich import print as pprint
|
|
145
|
+
from rich.panel import Panel
|
|
146
|
+
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))
|
|
147
|
+
new_exe_name = self.exe_name + ".exe" if platform.system() == "Windows" else self.exe_name
|
|
148
|
+
exe.with_name(name=new_exe_name, inplace=True, overwrite=True)
|
|
149
|
+
INSTALL_VERSION_ROOT.joinpath(self.exe_name).create(parents_only=True).write_text(version_to_be_installed)
|
|
150
|
+
|
|
151
|
+
def download(self, version: Optional[str]):
|
|
89
152
|
if "github" not in self.repo_url or ".zip" in self.repo_url or ".tar.gz" in self.repo_url:
|
|
90
153
|
download_link = P(self.repo_url)
|
|
154
|
+
version_to_be_installed = "predefined_url"
|
|
155
|
+
print(f"📦️ Version to be installed: {version_to_be_installed}")
|
|
156
|
+
elif "http" in self.filename_template_linux_amd_64 or "http" in self.filename_template_windows_amd_64:
|
|
157
|
+
if platform.system() == "Windows":
|
|
158
|
+
download_link = P(self.filename_template_windows_amd_64)
|
|
159
|
+
elif platform.system() == "Linux":
|
|
160
|
+
download_link = P(self.filename_template_linux_amd_64)
|
|
161
|
+
else: raise NotImplementedError(f"📦️ System {platform.system()} not implemented")
|
|
162
|
+
version_to_be_installed = "predefined_url"
|
|
91
163
|
else:
|
|
92
164
|
release_url, version_to_be_installed = self.get_github_release(repo_url=self.repo_url, version=version)
|
|
165
|
+
print(f"📦️ Version to be installed: {version_to_be_installed}")
|
|
166
|
+
print(f"📦️ Release URL: {release_url}")
|
|
93
167
|
version_to_be_installed_stripped = version_to_be_installed.replace("v", "") if self.strip_v else version_to_be_installed
|
|
94
168
|
if platform.system() == "Windows":
|
|
95
169
|
file_name = self.filename_template_windows_amd_64.format(version_to_be_installed_stripped)
|
|
96
170
|
elif platform.system() == "Linux":
|
|
97
171
|
file_name = self.filename_template_linux_amd_64.format(version_to_be_installed_stripped)
|
|
98
|
-
else: raise NotImplementedError(f"System {platform.system()} not implemented")
|
|
172
|
+
else: raise NotImplementedError(f"📦️ System {platform.system()} not implemented")
|
|
173
|
+
print(f"📦️ File name", file_name)
|
|
99
174
|
download_link = release_url.joinpath(file_name)
|
|
100
|
-
print("Downloading", download_link.as_url_str())
|
|
175
|
+
print(f"📦️ Downloading {self.name}: ", download_link.as_url_str())
|
|
101
176
|
downloaded = download_link.download(folder=INSTALL_TMP_DIR).decompress()
|
|
102
|
-
|
|
103
|
-
elif platform.system() == "Linux": exe = find_move_delete_linux(downloaded=downloaded, tool_name=self.exe_name, delete=True, rename_to=self.exe_name)
|
|
104
|
-
else: raise NotImplementedError(f"System {platform.system()} not implemented")
|
|
105
|
-
if exe.name.replace(".exe", "") != self.exe_name:
|
|
106
|
-
from rich import print as pprint
|
|
107
|
-
from rich.panel import Panel
|
|
108
|
-
pprint(Panel(f"Expected exe name, [red]{self.exe_name}! Attained name: {exe.name}", title="exe mismatch", subtitle=self.repo_url))
|
|
177
|
+
return downloaded, version_to_be_installed
|
|
109
178
|
|
|
110
179
|
@staticmethod
|
|
111
180
|
def get_github_release(repo_url: str, version: Optional[str] = None):
|
|
112
181
|
print("\n\n\n")
|
|
113
|
-
print(f"Inspecting latest release @ {repo_url} ...")
|
|
182
|
+
print(f"📦️ Inspecting latest release @ {repo_url} ...")
|
|
114
183
|
# with console.status("Installing..."): # makes troubles on linux when prompt asks for password to move file to /usr/bin
|
|
115
184
|
if version is None:
|
|
185
|
+
# see this: https://api.github.com/repos/cointop-sh/cointop/releases/latest
|
|
116
186
|
import requests # https://docs.github.com/en/repositories/releasing-projects-on-github/linking-to-releases
|
|
117
187
|
_latest_version = requests.get(str(repo_url) + "/releases/latest", timeout=10).url.split("/")[-1] # this is to resolve the redirection that occures: https://stackoverflow.com/questions/36070821/how-to-get-redirect-url-using-python-requests
|
|
118
188
|
version_to_be_installed = _latest_version
|
|
189
|
+
# print(version_to_be_installed)
|
|
119
190
|
else:
|
|
120
191
|
version_to_be_installed = version
|
|
121
192
|
release_url = P(repo_url + "/releases/download/" + version_to_be_installed)
|
|
122
193
|
return release_url, version_to_be_installed
|
|
123
194
|
|
|
124
195
|
@staticmethod
|
|
125
|
-
def check_if_installed_already(exe_name: str, version: str):
|
|
196
|
+
def check_if_installed_already(exe_name: str, version: str, use_cache: bool):
|
|
126
197
|
version_to_be_installed = version
|
|
127
|
-
# existing_version_cli = Terminal().run(f"{exe_name or tool_name} --version", shell="powershell").op_if_successfull_or_default(strict_err=True, strict_returcode=True)
|
|
128
198
|
tmp_path = INSTALL_VERSION_ROOT.joinpath(exe_name).create(parents_only=True)
|
|
129
|
-
|
|
130
|
-
|
|
199
|
+
|
|
200
|
+
if use_cache:
|
|
201
|
+
if tmp_path.exists(): existing_version = tmp_path.read_text().rstrip()
|
|
202
|
+
else: existing_version = None
|
|
203
|
+
else:
|
|
204
|
+
# check_tool_exists(tool_name=exe_name)
|
|
205
|
+
# raise NotImplementedError("Not implemented")
|
|
206
|
+
# import subprocess
|
|
207
|
+
# try:
|
|
208
|
+
# existing_version = subprocess.check_output([exe_name, "--version"], text=True)
|
|
209
|
+
# existing_version = existing_version.strip()
|
|
210
|
+
# except (subprocess.CalledProcessError, FileNotFoundError):
|
|
211
|
+
# print(f"Failed to get version of {exe_name}")
|
|
212
|
+
# existing_version = None
|
|
213
|
+
resp = Terminal().run(exe_name, "--version", check=False).capture()
|
|
214
|
+
if resp.op == '': existing_version = None
|
|
215
|
+
else: existing_version = resp.op.strip()
|
|
131
216
|
|
|
132
217
|
if existing_version is not None:
|
|
133
218
|
if existing_version == version_to_be_installed:
|
|
134
|
-
print(f"⚠️ {exe_name} already installed at version {version_to_be_installed}. See {INSTALL_VERSION_ROOT}")
|
|
135
|
-
return
|
|
219
|
+
print(f"📦️ ⚠️ {exe_name} already installed at version {version_to_be_installed}. See {INSTALL_VERSION_ROOT}")
|
|
220
|
+
return ("✅ Uptodate", version.strip(), version_to_be_installed.strip())
|
|
136
221
|
else:
|
|
137
222
|
# print(f"Latest version is {version}, logged at {tmp_path}")
|
|
138
|
-
print(f"⬆️ {exe_name} installed at version {existing_version.rstrip()} --> Installing version {version_to_be_installed} ")
|
|
223
|
+
print(f"📦️ ⬆️ {exe_name} installed at version {existing_version.rstrip()} --> Installing version {version_to_be_installed} ")
|
|
139
224
|
tmp_path.write_text(version_to_be_installed)
|
|
225
|
+
return ("❌ Outdated", existing_version.strip(), version_to_be_installed.strip())
|
|
140
226
|
else:
|
|
141
|
-
print(f"{exe_name} has no known version. Installing version `{version_to_be_installed}` ")
|
|
227
|
+
print(f"📦️ {exe_name} has no known version. Installing version `{version_to_be_installed}` ")
|
|
142
228
|
tmp_path.write_text(version_to_be_installed)
|
|
143
|
-
return
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
# ------------------------ ARCHIVE ------------------------
|
|
147
|
-
@dataclass
|
|
148
|
-
class ReleaseFileNameStructure:
|
|
149
|
-
repo_url: str
|
|
150
|
-
fixed_file_name_windows_amd_64: Optional[str] # the release has a fixed file name, so no need to compose it
|
|
151
|
-
fixed_file_name_linux_amd_64: Optional[str] # the release has a fixed file name, so no need to compose it
|
|
152
|
-
tool_name: str # as it appears in the release file name
|
|
153
|
-
exe_name: str # as it is called from the terminal, i.e. the name of the executable file
|
|
154
|
-
suffix_window_amd_64: Optional[str]
|
|
155
|
-
suffix_linux_amd_64: Optional[str]
|
|
156
|
-
compression_windows: Optional[str]
|
|
157
|
-
compression_linux: Optional[str]
|
|
158
|
-
sep: str = "-"
|
|
159
|
-
strip_v: bool = False
|
|
160
|
-
doc: str = ""
|
|
161
|
-
|
|
162
|
-
def to_dict(self):
|
|
163
|
-
return self.__dict__
|
|
229
|
+
return ("⚠️NotInstalled", "None", version_to_be_installed.strip())
|
|
164
230
|
|
|
165
|
-
@staticmethod
|
|
166
|
-
def from_dict(d: dict[str, Any]):
|
|
167
|
-
return ReleaseFileNameStructure(**d)
|
|
168
|
-
|
|
169
|
-
def compose_filename(self, version: Optional[str]) -> str:
|
|
170
|
-
if platform.system() == "Windows": fixed_file_name = self.fixed_file_name_windows_amd_64
|
|
171
|
-
elif platform.system() == "Linux": fixed_file_name = self.fixed_file_name_linux_amd_64
|
|
172
|
-
else: raise NotImplementedError(f"System {platform.system()} not implemented")
|
|
173
|
-
if fixed_file_name is not None: return fixed_file_name
|
|
174
|
-
assert version is not None, f"Version must be passed if fixed_file_name is None"
|
|
175
|
-
version_in_filename = version.replace("v", "") if self.strip_v else version
|
|
176
|
-
if platform.system() == "Windows":
|
|
177
|
-
compression = self.compression_windows
|
|
178
|
-
suffix = self.suffix_window_amd_64
|
|
179
|
-
assert suffix is not None, f"No binaries for windows found for {self.tool_name}"
|
|
180
|
-
elif platform.system() == "Linux":
|
|
181
|
-
compression = self.compression_linux
|
|
182
|
-
suffix = self.suffix_linux_amd_64
|
|
183
|
-
assert suffix is not None, f"No binaries for linux found for {self.tool_name}"
|
|
184
|
-
else: raise NotImplementedError(f"System {platform.system()} not implemented")
|
|
185
|
-
file_name = f'{self.tool_name}{self.sep}{version_in_filename}{self.sep}{suffix}'
|
|
186
|
-
if compression is not None: file_name += f".{compression}"
|
|
187
|
-
return file_name
|
|
188
|
-
|
|
189
|
-
def compose_download_link(self, version: Optional[str]):
|
|
190
|
-
release_url, version_to_be_installed = Installer.get_github_release(repo_url=self.repo_url, version=version)
|
|
191
|
-
file_name = self.compose_filename(version=version_to_be_installed)
|
|
192
|
-
download_link = release_url.joinpath(file_name)
|
|
193
|
-
return download_link
|
|
194
|
-
|
|
195
|
-
def install(self, version: Optional[str] = None):
|
|
196
|
-
gh_release = self
|
|
197
|
-
release_url, version_to_be_installed = Installer.get_github_release(repo_url=gh_release.repo_url, version=version)
|
|
198
|
-
installed_already = Installer.check_if_installed_already(exe_name=gh_release.exe_name, version=version_to_be_installed)
|
|
199
|
-
|
|
200
|
-
if installed_already: return None
|
|
201
|
-
# if not download_n_extract: return release_url
|
|
202
|
-
console = Console()
|
|
203
|
-
console.rule(f"Installing {gh_release.exe_name} version {version_to_be_installed}")
|
|
204
|
-
file_name = gh_release.compose_filename(version=version_to_be_installed)
|
|
205
|
-
download_link = release_url.joinpath(file_name)
|
|
206
|
-
|
|
207
|
-
print("Downloading", download_link.as_url_str())
|
|
208
|
-
downloaded = download_link.download(folder=INSTALL_TMP_DIR).decompress()
|
|
209
|
-
if not platform.system() == "Linux": return find_move_delete_windows(downloaded_file_path=downloaded, exe_name=gh_release.exe_name, delete=True)
|
|
210
|
-
return find_move_delete_linux(downloaded=downloaded, tool_name=gh_release.exe_name, delete=True)
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
def get_latest_release(repo_url: str, exe_name: str,
|
|
214
|
-
download_n_extract: bool = False,
|
|
215
|
-
suffix: Optional[str] = "x86_64-pc-windows-msvc",
|
|
216
|
-
file_name: Optional[str] = None, # e.g. windows_x86_64.zip
|
|
217
|
-
tool_name: Optional[str] = None,
|
|
218
|
-
delete: bool = True, strip_v: bool = False,
|
|
219
|
-
compression: Optional[str] = None,
|
|
220
|
-
sep: str = "-", version: Optional[str] = None):
|
|
221
|
-
"""Arguments help form last part of URL `filename = f'{tool_name}{sep}{version}{sep}{suffix}.{compression}'`
|
|
222
|
-
Unless `file_name` is passed directly, in which case it is used as is and parameters above are ignored.
|
|
223
|
-
"""
|
|
224
|
-
|
|
225
|
-
console = Console()
|
|
226
|
-
if platform.system() == "Windows":
|
|
227
|
-
gh_release = ReleaseFileNameStructure(repo_url=repo_url, fixed_file_name_linux_amd_64=None, fixed_file_name_windows_amd_64=file_name,
|
|
228
|
-
tool_name=tool_name or exe_name, exe_name=exe_name,
|
|
229
|
-
suffix_window_amd_64=suffix, suffix_linux_amd_64=suffix, compression_windows=compression, compression_linux=compression, sep=sep, strip_v=strip_v)
|
|
230
|
-
elif platform.system() == "Linux":
|
|
231
|
-
gh_release = ReleaseFileNameStructure(repo_url=repo_url, fixed_file_name_windows_amd_64=None, fixed_file_name_linux_amd_64=file_name, tool_name=tool_name or exe_name, exe_name=exe_name, suffix_window_amd_64=suffix, suffix_linux_amd_64=suffix, compression_windows=compression, compression_linux=compression, sep=sep, strip_v=strip_v)
|
|
232
|
-
else: raise NotImplementedError(f"System {platform.system()} not implemented")
|
|
233
|
-
|
|
234
|
-
release_url, version_to_be_installed = Installer.get_github_release(repo_url=gh_release.repo_url, version=version)
|
|
235
|
-
installed_already = Installer.check_if_installed_already(exe_name=exe_name, version=version_to_be_installed)
|
|
236
|
-
|
|
237
|
-
if installed_already: return None
|
|
238
|
-
if not download_n_extract: return release_url
|
|
239
|
-
|
|
240
|
-
console.rule(f"Installing {exe_name} version {version_to_be_installed}")
|
|
241
|
-
file_name = gh_release.compose_filename(version=version_to_be_installed)
|
|
242
|
-
download_link = release_url.joinpath(file_name)
|
|
243
|
-
|
|
244
|
-
print("Downloading", download_link.as_url_str())
|
|
245
|
-
downloaded = download_link.download(folder=INSTALL_TMP_DIR).decompress()
|
|
246
|
-
if not platform.system() == "Linux": return find_move_delete_windows(downloaded_file_path=downloaded, exe_name=exe_name, delete=delete)
|
|
247
|
-
return find_move_delete_linux(downloaded=downloaded, tool_name=exe_name, delete=delete)
|
|
248
|
-
# console.rule(f"Completed Installation")
|
|
249
|
-
# return res
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
def run_python_installer(py_file: P, version: Optional[str] = None):
|
|
253
|
-
try:
|
|
254
|
-
old_version = Terminal().run(f"{py_file.stem} --version", shell="powershell").op.replace("\n", "")
|
|
255
|
-
Read.py(py_file)["main"](version=version)
|
|
256
|
-
new_version = Terminal().run(f"{py_file.stem} --version", shell="powershell").op.replace("\n", "")
|
|
257
|
-
if old_version == new_version: return f"😑 {py_file.stem}, same version: {old_version}"
|
|
258
|
-
else: return f"🤩 {py_file.stem} updated from {old_version} === to ===> {new_version}"
|
|
259
|
-
except Exception as ex:
|
|
260
|
-
print(ex)
|
|
261
|
-
return f"Failed at {py_file.stem} with {ex}"
|
|
262
|
-
|
|
263
|
-
def get_cli_py_installers(system: str, dev: bool, use_config: bool = False):
|
|
264
|
-
if system == "Windows": import machineconfig.jobs.python_windows_installers as inst
|
|
265
|
-
else: import machineconfig.jobs.python_linux_installers as inst
|
|
266
|
-
import machineconfig.jobs.python_generic_installers as gens
|
|
267
|
-
path = P(inst.__file__).parent
|
|
268
|
-
gens_path = P(gens.__file__).parent
|
|
269
|
-
if dev:
|
|
270
|
-
path = path.joinpath("dev")
|
|
271
|
-
gens_path = gens_path.joinpath("dev")
|
|
272
|
-
if use_config: return L([path.joinpath("config.json"), gens_path.joinpath("config.json")])
|
|
273
|
-
return path.search("*.py", filters=[lambda x: "__init__" not in str(x)]) + gens_path.search("*.py", filters=[lambda x: "__init__" not in str(x)])
|
|
274
|
-
|
|
275
|
-
def install_all(installers: L[P], safe: bool = False, jobs: int = 10, fresh: bool = False):
|
|
276
|
-
if fresh: INSTALL_VERSION_ROOT.delete(sure=True)
|
|
277
|
-
if safe:
|
|
278
|
-
from machineconfig.jobs.python.check_installations import APP_SUMMARY_PATH
|
|
279
|
-
apps_dir = APP_SUMMARY_PATH.readit()
|
|
280
|
-
if platform.system().lower() == "windows":
|
|
281
|
-
apps_dir.search("*").apply(lambda app: app.move(folder=P.get_env().WindowsApps))
|
|
282
|
-
elif platform.system().lower() == "linux":
|
|
283
|
-
Terminal().run(f"sudo mv {apps_dir.as_posix()}/* /usr/local/bin/").print_if_unsuccessful(desc="MOVING executable to /usr/local/bin", strict_err=True, strict_returncode=True)
|
|
284
|
-
else: raise NotImplementedError(f"I don't know this system {platform.system()}")
|
|
285
|
-
apps_dir.delete(sure=True)
|
|
286
|
-
return None
|
|
287
231
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
print("\n")
|
|
299
|
-
console.rule("Failed apps")
|
|
300
|
-
print(f"{res.filter(lambda x: 'Failed at' in x).print()}")
|
|
232
|
+
def check_latest():
|
|
233
|
+
installers = get_installers(system=platform.system(), dev=False)
|
|
234
|
+
# installers += get_installers(system=platform.system(), dev=True)
|
|
235
|
+
installers_gitshub = []
|
|
236
|
+
for inst__ in installers:
|
|
237
|
+
if "ntop" in inst__.name: continue
|
|
238
|
+
if "github" not in inst__.repo_url:
|
|
239
|
+
print(f"Skipping {inst__.name} as it is not a github release")
|
|
240
|
+
continue
|
|
241
|
+
installers_gitshub.append(inst__)
|
|
301
242
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
243
|
+
def func(inst: Installer):
|
|
244
|
+
_release_url, version_to_be_installed = inst.get_github_release(repo_url=inst.repo_url, version=None)
|
|
245
|
+
verdict, current_ver, new_ver = inst.check_if_installed_already(exe_name=inst.exe_name, version=version_to_be_installed, use_cache=False)
|
|
246
|
+
return inst.exe_name, verdict, current_ver, new_ver
|
|
305
247
|
|
|
306
|
-
|
|
248
|
+
res = L(installers_gitshub).apply(func=func, jobs=1)
|
|
249
|
+
import pandas as pd
|
|
250
|
+
res_df = pd.DataFrame(res, columns=["Tool", "Status", "Current Version", "New Version"]).groupby("Status").apply(lambda x: x).reset_index(drop=True)
|
|
251
|
+
from crocodile.core import Display
|
|
252
|
+
Display.set_pandas_display()
|
|
253
|
+
print(res_df)
|
|
307
254
|
|
|
308
255
|
|
|
309
256
|
def get_installed_cli_apps():
|
|
310
257
|
if platform.system() == "Windows": apps = P.home().joinpath("AppData/Local/Microsoft/WindowsApps").search("*.exe", not_in=["notepad"])
|
|
311
|
-
elif platform.system() == "Linux": apps = P(
|
|
258
|
+
elif platform.system() == "Linux": apps = P(LINUX_INSTALL_PATH).search("*")
|
|
312
259
|
else: raise NotImplementedError("Not implemented for this OS")
|
|
313
260
|
apps = L([app for app in apps if app.size("kb") > 0.1 and not app.is_symlink()]) # no symlinks like paint and wsl and bash
|
|
314
261
|
return apps
|
|
315
262
|
|
|
316
263
|
|
|
317
|
-
def
|
|
318
|
-
if system == "Windows": import machineconfig.jobs.python_windows_installers as
|
|
319
|
-
else: import machineconfig.jobs.python_linux_installers as
|
|
320
|
-
import machineconfig.jobs.python_generic_installers as
|
|
321
|
-
|
|
322
|
-
|
|
264
|
+
def get_installers(system: str, dev: bool) -> list[Installer]:
|
|
265
|
+
if system == "Windows": import machineconfig.jobs.python_windows_installers as os_specific_installer
|
|
266
|
+
else: import machineconfig.jobs.python_linux_installers as os_specific_installer
|
|
267
|
+
import machineconfig.jobs.python_generic_installers as generic_installer
|
|
268
|
+
path_os_specific = P(os_specific_installer.__file__).parent
|
|
269
|
+
path_os_generic = P(generic_installer.__file__).parent
|
|
270
|
+
path_custom_installer = path_os_generic.with_name("python_custom_installers")
|
|
323
271
|
if dev:
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
res1: dict[str, Any] = Read.json(path=
|
|
327
|
-
res2: dict[str, Any] = Read.json(path=
|
|
272
|
+
path_os_specific = path_os_specific.joinpath("dev")
|
|
273
|
+
path_os_generic = path_os_generic.joinpath("dev")
|
|
274
|
+
res1: dict[str, Any] = Read.json(path=path_os_specific.joinpath("config.json"))
|
|
275
|
+
res2: dict[str, Any] = Read.json(path=path_os_generic.joinpath("config.json"))
|
|
328
276
|
res2.update(res1)
|
|
329
|
-
|
|
277
|
+
import runpy
|
|
278
|
+
for item in path_custom_installer.search("*.py", r=False):
|
|
279
|
+
try:
|
|
280
|
+
config_dict = runpy.run_path(str(item), run_name=None)['config_dict']
|
|
281
|
+
res2[item.stem] = config_dict
|
|
282
|
+
except Exception as ex:
|
|
283
|
+
print(f"Failed to load {item}: {ex}")
|
|
284
|
+
|
|
285
|
+
return [Installer.from_dict(d=vd, name=k) for k, vd in res2.items()]
|
|
330
286
|
|
|
331
287
|
|
|
332
|
-
def
|
|
288
|
+
def install_all(installers: L[Installer], safe: bool = False, jobs: int = 10, fresh: bool = False):
|
|
333
289
|
if fresh: INSTALL_VERSION_ROOT.delete(sure=True)
|
|
334
290
|
if safe:
|
|
335
291
|
from machineconfig.jobs.python.check_installations import APP_SUMMARY_PATH
|
|
@@ -337,7 +293,7 @@ def install_all_v2(installers: L[Installer], safe: bool = False, jobs: int = 10,
|
|
|
337
293
|
if platform.system().lower() == "windows":
|
|
338
294
|
apps_dir.search("*").apply(lambda app: app.move(folder=P.get_env().WindowsApps))
|
|
339
295
|
elif platform.system().lower() == "linux":
|
|
340
|
-
Terminal().run(f"sudo mv {apps_dir.as_posix()}/* /
|
|
296
|
+
Terminal().run(f"sudo mv {apps_dir.as_posix()}/* {LINUX_INSTALL_PATH}/").print_if_unsuccessful(desc=f"MOVING executable to {LINUX_INSTALL_PATH}", strict_err=True, strict_returncode=True)
|
|
341
297
|
else: raise NotImplementedError(f"I don't know this system {platform.system()}")
|
|
342
298
|
apps_dir.delete(sure=True)
|
|
343
299
|
return None
|
|
@@ -357,3 +313,7 @@ def install_all_v2(installers: L[Installer], safe: bool = False, jobs: int = 10,
|
|
|
357
313
|
print("\n")
|
|
358
314
|
print("Completed Installation".center(100, "-"))
|
|
359
315
|
print("\n" * 2)
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
if __name__ == "__main__":
|
|
319
|
+
pass
|