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.

Files changed (72) hide show
  1. machineconfig/__init__.py +4 -2
  2. machineconfig/jobs/python/check_installations.py +38 -32
  3. machineconfig/jobs/python/create_bootable_media.py +4 -4
  4. machineconfig/jobs/python/create_zellij_template.py +3 -2
  5. machineconfig/jobs/python/python_cargo_build_share.py +14 -9
  6. machineconfig/jobs/python/python_ve_symlink.py +6 -6
  7. machineconfig/jobs/python_custom_installers/azuredatastudio.py +36 -0
  8. machineconfig/jobs/python_custom_installers/bypass_paywall.py +30 -0
  9. machineconfig/jobs/{python_linux_installers/dev → python_custom_installers}/docker_desktop.py +15 -4
  10. machineconfig/jobs/python_custom_installers/gh.py +53 -0
  11. machineconfig/jobs/python_custom_installers/goes.py +35 -0
  12. machineconfig/jobs/python_custom_installers/helix.py +43 -0
  13. machineconfig/jobs/python_custom_installers/lvim.py +48 -0
  14. machineconfig/jobs/python_custom_installers/ngrok.py +39 -0
  15. machineconfig/jobs/python_custom_installers/nvim.py +48 -0
  16. machineconfig/jobs/python_custom_installers/vscode.py +45 -0
  17. machineconfig/jobs/python_custom_installers/wezterm.py +41 -0
  18. machineconfig/profile/create.py +12 -7
  19. machineconfig/profile/shell.py +15 -13
  20. machineconfig/scripts/python/choose_wezterm_theme.py +96 -0
  21. machineconfig/scripts/python/cloud_copy.py +18 -13
  22. machineconfig/scripts/python/cloud_mount.py +41 -15
  23. machineconfig/scripts/python/cloud_repo_sync.py +57 -31
  24. machineconfig/scripts/python/cloud_sync.py +13 -15
  25. machineconfig/scripts/python/croshell.py +19 -10
  26. machineconfig/scripts/python/devops.py +22 -6
  27. machineconfig/scripts/python/devops_add_identity.py +7 -6
  28. machineconfig/scripts/python/devops_add_ssh_key.py +10 -9
  29. machineconfig/scripts/python/devops_backup_retrieve.py +5 -5
  30. machineconfig/scripts/python/devops_devapps_install.py +24 -19
  31. machineconfig/scripts/python/devops_update_repos.py +5 -4
  32. machineconfig/scripts/python/dotfile.py +8 -4
  33. machineconfig/scripts/python/fire_jobs.py +165 -55
  34. machineconfig/scripts/python/ftpx.py +18 -8
  35. machineconfig/scripts/python/mount_nfs.py +13 -10
  36. machineconfig/scripts/python/mount_nw_drive.py +4 -3
  37. machineconfig/scripts/python/mount_ssh.py +8 -5
  38. machineconfig/scripts/python/repos.py +26 -21
  39. machineconfig/scripts/python/snapshot.py +2 -2
  40. machineconfig/scripts/python/start_slidev.py +104 -0
  41. machineconfig/scripts/python/start_terminals.py +1 -1
  42. machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +20 -34
  43. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +11 -12
  44. machineconfig/utils/installer.py +177 -217
  45. machineconfig/utils/scheduling.py +1 -1
  46. machineconfig/utils/utils.py +107 -54
  47. machineconfig/utils/ve.py +120 -16
  48. machineconfig-1.9.dist-info/LICENSE +201 -0
  49. {machineconfig-1.7.dist-info → machineconfig-1.9.dist-info}/METADATA +155 -140
  50. machineconfig-1.9.dist-info/RECORD +76 -0
  51. {machineconfig-1.7.dist-info → machineconfig-1.9.dist-info}/WHEEL +1 -1
  52. machineconfig/jobs/python_generic_installers/archive/gopass.py +0 -18
  53. machineconfig/jobs/python_generic_installers/archive/nvim.py +0 -20
  54. machineconfig/jobs/python_generic_installers/archive/opencommit.py +0 -25
  55. machineconfig/jobs/python_generic_installers/archive/strongbox.py +0 -33
  56. machineconfig/jobs/python_generic_installers/dev/__init__.py +0 -0
  57. machineconfig/jobs/python_linux_installers/archive/__init__.py +0 -0
  58. machineconfig/jobs/python_linux_installers/archive/bandwhich.py +0 -14
  59. machineconfig/jobs/python_linux_installers/archive/ranger.py +0 -19
  60. machineconfig/jobs/python_linux_installers/dev/azure_data_studio.py +0 -21
  61. machineconfig/jobs/python_linux_installers/dev/bytehound.py +0 -20
  62. machineconfig/jobs/python_linux_installers/dev/nnn.py +0 -22
  63. machineconfig/jobs/python_windows_installers/archive/ntop.py +0 -21
  64. machineconfig/jobs/python_windows_installers/dev/bypass_paywall.py +0 -22
  65. machineconfig/jobs/python_windows_installers/dev/obs_background_removal_plugin.py +0 -22
  66. machineconfig/scripts/python/choose_ohmybash_theme.py +0 -31
  67. machineconfig/scripts/python/choose_ohmyposh_theme.py +0 -57
  68. machineconfig/utils/pandas_type.py +0 -37
  69. machineconfig/utils/to_exe.py +0 -7
  70. machineconfig-1.7.dist-info/RECORD +0 -81
  71. /machineconfig/jobs/{python_generic_installers/archive → python_custom_installers}/__init__.py +0 -0
  72. {machineconfig-1.7.dist-info → machineconfig-1.9.dist-info}/top_level.txt +0 -0
@@ -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: exe = downloaded_file_path.search("*.exe", r=True).list[0]
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=P.get_env().WindowsApps, overwrite=True) # latest version overwrites older installation.
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 exe
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: exe = downloaded.search(tool_name, folders=False, r=True).list[0]
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 '/usr/local/bin'")
59
+ print(f"MOVING file `{repr(exe)}` to '{LINUX_INSTALL_PATH}'")
42
60
  exe.chmod(0o777)
43
- # exe.move(folder=r"/usr/local/bin", overwrite=False)
44
- Terminal().run(f"sudo mv {exe} /usr/local/bin/").print_if_unsuccessful(desc="MOVING executable to /usr/local/bin", strict_err=True, strict_returncode=True)
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
- return exe
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): return f"{self.exe_name} -- {self.doc}"
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 choose_and_install():
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
- # binary = choose_one_option(options=list(config.keys()), fzf=True)
72
- for binary in list(config.keys()):
73
- installer = Installer.from_dict(config[binary])
74
- installer.install(version=None)
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
- old_version = Terminal().run(f"{self.exe_name} --version", shell="powershell").op.replace("\n", "")
105
+ old_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
79
106
  self.install(version=version)
80
- new_version = Terminal().run(f"{self.exe_name} --version", shell="powershell").op.replace("\n", "")
81
- if old_version == new_version: return f"😑 {self.exe_name}, same version: {old_version}"
82
- else: return f"🤩 {self.exe_name} updated from {old_version} === to ===> {new_version}"
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
- if platform.system() == "Windows": exe = find_move_delete_windows(downloaded_file_path=downloaded, exe_name=self.exe_name, delete=True, rename_to=self.exe_name + ".exe")
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
- if tmp_path.exists(): existing_version = tmp_path.read_text().rstrip()
130
- else: existing_version = None
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 True
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 False
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
- run_python_installer(installers.list[0]) # try out the first installer alone cause it will ask for password, so the rest will inherit the sudo session.
289
- # summarize results
290
- res: L[str] = installers.slice(start=1).apply(run_python_installer, jobs=jobs)
291
- console = Console()
292
- print("\n")
293
- console.rule("Same version apps")
294
- print(f"{res.filter(lambda x: 'same version' in x).print()}")
295
- print("\n")
296
- console.rule("Updated apps")
297
- print(f"{res.filter(lambda x: 'updated from' in x).print()}")
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
- print("\n")
303
- print("Completed Installation".center(100, "-"))
304
- print("\n" * 2)
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
- # ------------------------ ARCHIVE ------------------------
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(r"/usr/local/bin").search("*")
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 get_cli_py_installers_v2(system: str, dev: bool) -> list[Installer]:
318
- if system == "Windows": import machineconfig.jobs.python_windows_installers as inst
319
- else: import machineconfig.jobs.python_linux_installers as inst
320
- import machineconfig.jobs.python_generic_installers as gens
321
- path = P(inst.__file__).parent
322
- gens_path = P(gens.__file__).parent
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
- path = path.joinpath("dev")
325
- gens_path = gens_path.joinpath("dev")
326
- res1: dict[str, Any] = Read.json(path=path.joinpath("config.json"))
327
- res2: dict[str, Any] = Read.json(path=gens_path.joinpath("config.json"))
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
- return [Installer.from_dict(d) for d in res2.values()]
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 install_all_v2(installers: L[Installer], safe: bool = False, jobs: int = 10, fresh: bool = False):
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()}/* /usr/local/bin/").print_if_unsuccessful(desc="MOVING executable to /usr/local/bin", strict_err=True, strict_returncode=True)
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
@@ -19,7 +19,7 @@ SUCCESS = "success"
19
19
  DEFAULT_CONFIG = """
20
20
  [specs]
21
21
  frequency = 30d
22
- start = 2023-11-01 01:00
22
+ start = 2024-01-01 01:00
23
23
 
24
24
  [runtime]
25
25
  venv = ve