machineconfig 1.9__py3-none-any.whl → 1.91__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 (53) hide show
  1. machineconfig/__init__.py +1 -1
  2. machineconfig/jobs/python/check_installations.py +7 -5
  3. machineconfig/jobs/python/checkout_version.py +27 -32
  4. machineconfig/jobs/python/create_bootable_media.py +1 -1
  5. machineconfig/jobs/python/python_cargo_build_share.py +2 -2
  6. machineconfig/jobs/python/tasks.py +2 -2
  7. machineconfig/jobs/python_custom_installers/{helix.py → hx.py} +17 -5
  8. machineconfig/profile/create.py +23 -21
  9. machineconfig/profile/create_hardlinks.py +101 -0
  10. machineconfig/profile/shell.py +5 -5
  11. machineconfig/scripts/python/cloud_copy.py +19 -16
  12. machineconfig/scripts/python/cloud_repo_sync.py +92 -47
  13. machineconfig/scripts/python/cloud_sync.py +70 -63
  14. machineconfig/scripts/python/croshell.py +6 -6
  15. machineconfig/scripts/python/devops.py +19 -20
  16. machineconfig/scripts/python/devops_backup_retrieve.py +19 -10
  17. machineconfig/scripts/python/devops_devapps_install.py +80 -62
  18. machineconfig/scripts/python/devops_update_repos.py +5 -5
  19. machineconfig/scripts/python/dotfile.py +4 -4
  20. machineconfig/scripts/python/fire_jobs.py +57 -23
  21. machineconfig/scripts/python/gh_models.py +53 -0
  22. machineconfig/scripts/python/mount_nfs.py +1 -1
  23. machineconfig/scripts/python/mount_nw_drive.py +3 -3
  24. machineconfig/scripts/python/mount_ssh.py +2 -3
  25. machineconfig/scripts/python/pomodoro.py +1 -1
  26. machineconfig/scripts/python/repos.py +21 -22
  27. machineconfig/scripts/python/scheduler.py +1 -1
  28. machineconfig/scripts/python/start_slidev.py +10 -4
  29. machineconfig/scripts/python/start_terminals.py +5 -4
  30. machineconfig/scripts/python/wifi_conn.py +34 -42
  31. machineconfig/scripts/python/wsl_windows_transfer.py +1 -1
  32. machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +1 -1
  33. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +3 -2
  34. machineconfig/utils/installer.py +78 -39
  35. machineconfig/utils/procs.py +2 -2
  36. machineconfig/utils/scheduling.py +3 -3
  37. machineconfig/utils/utils.py +131 -52
  38. machineconfig/utils/ve.py +145 -95
  39. {machineconfig-1.9.dist-info → machineconfig-1.91.dist-info}/METADATA +160 -155
  40. machineconfig-1.91.dist-info/RECORD +69 -0
  41. machineconfig/jobs/python_custom_installers/azuredatastudio.py +0 -36
  42. machineconfig/jobs/python_custom_installers/bypass_paywall.py +0 -30
  43. machineconfig/jobs/python_custom_installers/docker_desktop.py +0 -52
  44. machineconfig/jobs/python_custom_installers/goes.py +0 -35
  45. machineconfig/jobs/python_custom_installers/lvim.py +0 -48
  46. machineconfig/jobs/python_custom_installers/ngrok.py +0 -39
  47. machineconfig/jobs/python_custom_installers/nvim.py +0 -48
  48. machineconfig/jobs/python_custom_installers/vscode.py +0 -45
  49. machineconfig/jobs/python_custom_installers/wezterm.py +0 -41
  50. machineconfig-1.9.dist-info/RECORD +0 -76
  51. {machineconfig-1.9.dist-info → machineconfig-1.91.dist-info}/LICENSE +0 -0
  52. {machineconfig-1.9.dist-info → machineconfig-1.91.dist-info}/WHEEL +0 -0
  53. {machineconfig-1.9.dist-info → machineconfig-1.91.dist-info}/top_level.txt +0 -0
@@ -45,7 +45,7 @@ def main_parse():
45
45
  print(f"✅ Task {task_name} created in {task_root}. Head there and edit the config.ini file & task.py file.")
46
46
  return None
47
47
 
48
- main(root=root.str, ignore_conditions=args.ignore_conditions)
48
+ main(root=root.to_str(), ignore_conditions=args.ignore_conditions)
49
49
 
50
50
 
51
51
  if __name__ == "__main__":
@@ -16,7 +16,7 @@ PORT_DEFAULT = 3030
16
16
  SLIDEV_REPO = CONFIG_PATH.joinpath(".cache/slidev")
17
17
  if not SLIDEV_REPO.joinpath("components").exists():
18
18
  # assert slidev is installed first
19
- Terminal(stderr=subprocess.PIPE, stdin=subprocess.PIPE, stdout=subprocess.PIPE).run(f"cd {SLIDEV_REPO.parent};npm init slidev")
19
+ Terminal(stderr=subprocess.PIPE, stdin=subprocess.PIPE, stdout=subprocess.PIPE).run(f"cd {SLIDEV_REPO.parent};npm init slidev@latest")
20
20
 
21
21
 
22
22
  def jupyter_to_markdown(file: P):
@@ -55,10 +55,11 @@ def main() -> None:
55
55
  parser = argparse.ArgumentParser()
56
56
  parser.add_argument("-d", "--directory", default=None, help="Directory of the report")
57
57
  parser.add_argument("-j", "--jupyter-file", default=None, help="Jupyter notebook file to convert to slides. If not provided, slides.md is used.")
58
- parser.add_argument("--port", default=PORT_DEFAULT, help=f"Port to serve the report, default to {PORT_DEFAULT}")
58
+ # parser.add_argument("--port", default=PORT_DEFAULT, help=f"Port to serve the report, default to {PORT_DEFAULT}")
59
59
  args = parser.parse_args()
60
60
 
61
- port = args.port
61
+ # port = args.port
62
+ port = PORT_DEFAULT
62
63
 
63
64
  if args.jupyter_file is not None:
64
65
  report_dir = jupyter_to_markdown(P(args.jupyter_file))
@@ -95,7 +96,12 @@ def main() -> None:
95
96
  print(f"Presentation is served at http://{platform.node()}:{port}")
96
97
  print(f"Presentation is served at http://localhost:{port}")
97
98
  print(f"Presentation is served at http://{local_ip_v4}:{port}")
98
- program: str = f"cd {SLIDEV_REPO}; slidev --port {port} --remote 0.0.0.0; cd {P.cwd()}"
99
+ # This version requires a globally installed cli of slidev, which is not recommended.
100
+ # program: str=f"cd {SLIDEV_REPO}; slidev --port {port} --remote 0.0.0.0; cd {P.cwd()}"
101
+
102
+ # The recommended approach is do `npm init slidev@latest` in the directory where you want to create the presentation
103
+ # Then you can do the following:
104
+ program = "npm run dev slides.md -- --remote"
99
105
  PROGRAM_PATH.write_text(program)
100
106
  print_code(program, lexer="bash")
101
107
 
@@ -2,7 +2,7 @@
2
2
  """Script to start terminals on windows and wsl
3
3
  """
4
4
 
5
- from machineconfig.utils.utils import PROGRAM_PATH, display_options, install_n_import, get_ssh_hosts, platform
5
+ from machineconfig.utils.utils import PROGRAM_PATH, display_options, get_ssh_hosts, platform
6
6
  from itertools import cycle
7
7
  from typing import Literal
8
8
 
@@ -22,14 +22,14 @@ THIS_MACHINE_HOSTNAME = platform.node()
22
22
  THIS_MACHINE_HOSTNAME_WSL = f"{THIS_MACHINE_HOSTNAME}wsl"
23
23
 
24
24
 
25
- def main_windows_and_wsl(window: int, hosts: list[str], orientation: ORIENTATION_TYPE = "vertical", mprocs: bool = False):
25
+ def main_windows_and_wsl(window: int, hosts: list[str], orientation: ORIENTATION_TYPE = "vertical", mprocs: bool=False):
26
26
  orientation_oposite = "horizontal" if orientation == "vertical" else "vertical"
27
27
  orientation_swap = "up" if orientation == "horizontal" else "left"
28
28
  orientation_opposite_move_focus = "up" if orientation_oposite == "horizontal" else "left"
29
29
  orientation_opposite_move_focus_other = "down" if orientation_oposite == "horizontal" else "right"
30
30
  sleep = 3
31
31
  sep = f"\nsleep {sleep}; wt --window {window}" # or '`;'
32
- ssh_cmd = f"-t 'mprocs'" if mprocs else '' # 'wsl_ssh_windows_port_forwarding.ps1'
32
+ ssh_cmd = "-t 'mprocs'" if mprocs else '' # 'wsl_ssh_windows_port_forwarding.ps1'
33
33
  split_per_machine = 1 / len(hosts)
34
34
  size = 0.3
35
35
  known_hosts = get_ssh_hosts()
@@ -89,7 +89,8 @@ def main():
89
89
  cmd = main_windows_and_wsl(window=args.window, hosts=hosts, orientation="vertical" if args.vertical else "horizontal")
90
90
 
91
91
  print(cmd)
92
- install_n_import("clipboard").copy(cmd)
92
+ # import clipboard
93
+ # install_n_import("clipboard").copy(cmd)
93
94
  PROGRAM_PATH.write_text(cmd)
94
95
 
95
96
 
@@ -1,50 +1,44 @@
1
-
2
1
  """Wifi connect
2
+
3
+ sudo apt-get install network-manager
4
+
3
5
  """
4
6
 
5
7
  import argparse
6
8
  import configparser
7
9
  from pathlib import Path
8
- # import random
9
- # import string
10
10
  import os
11
-
11
+ import platform
12
+ import subprocess
12
13
 
13
14
  def create_new_connection(name: str, ssid: str, password: str):
14
- config = """<?xml version=\"1.0\"?>
15
- <WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
16
- <name>""" + name + """</name>
17
- <SSIDConfig>
18
- <SSID>
19
- <name>""" + ssid + """</name>
20
- </SSID>
21
- </SSIDConfig>
22
- <connectionType>ESS</connectionType>
23
- <connectionMode>auto</connectionMode>
24
- <MSM>
25
- <security>
26
- <authEncryption>
27
- <authentication>WPA2PSK</authentication>
28
- <encryption>AES</encryption>
29
- <useOneX>false</useOneX>
30
- </authEncryption>
31
- <sharedKey>
32
- <keyType>passPhrase</keyType>
33
- <protected>false</protected>
34
- <keyMaterial>""" + password + """</keyMaterial>
35
- </sharedKey>
36
- </security>
37
- </MSM>
38
- </WLANProfile>"""
39
- command = "netsh wlan add profile filename=\"" + name + ".xml\"" + " interface=Wi-Fi"
40
- with open(name + ".xml", mode='w', encoding="utf-8") as file: file.write(config)
41
- os.system(command)
42
-
15
+ if platform.system() == "Windows":
16
+ config = """<?xml version=\"1.0\"?>
17
+ // ...existing XML config...
18
+ """
19
+ command = "netsh wlan add profile filename=\"" + name + ".xml\"" + " interface=Wi-Fi"
20
+ with open(name + ".xml", mode='w', encoding="utf-8") as file:
21
+ file.write(config)
22
+ os.system(command)
23
+ elif platform.system() == "Linux":
24
+ # Use nmcli to add/update connection
25
+ command = f"nmcli connection add type wifi con-name '{name}' ssid '{ssid}' wifi-sec.key-mgmt wpa-psk wifi-sec.psk '{password}'"
26
+ subprocess.run(command, shell=True, check=True)
43
27
 
44
28
  def connect(name: str, ssid: str):
45
- command = "netsh wlan connect name=\"" + name + "\" ssid=\"" + ssid + "\" interface=Wi-Fi"
46
- os.system(command)
47
- def display_available_networks(): os.system("netsh wlan show networks interface=Wi-Fi") #
29
+ if platform.system() == "Windows":
30
+ command = "netsh wlan connect name=\"" + name + "\" ssid=\"" + ssid + "\" interface=Wi-Fi"
31
+ os.system(command)
32
+ elif platform.system() == "Linux":
33
+ command = f"nmcli connection up '{name}'"
34
+ subprocess.run(command, shell=True, check=True)
35
+
36
+
37
+ def display_available_networks():
38
+ if platform.system() == "Windows":
39
+ os.system("netsh wlan show networks interface=Wi-Fi")
40
+ elif platform.system() == "Linux":
41
+ subprocess.run("nmcli device wifi list", shell=True, check=True)
48
42
 
49
43
 
50
44
  def main():
@@ -52,20 +46,18 @@ def main():
52
46
  creds.read(Path.home().joinpath('dotfiles/machineconfig/setup/wifi.ini'))
53
47
 
54
48
  parser = argparse.ArgumentParser(description='Wifi Connector')
55
- parser.add_argument('-n', "--ssid", help=f"SSID of Wifi", default='MyPhoneHotSpot')
49
+ parser.add_argument('-n', "--ssid", help="SSID of Wifi", default='MyPhoneHotSpot')
56
50
 
57
51
  args = parser.parse_args()
58
52
  ssid = creds[args.ssid]['SSID']
59
- # pwd = creds[args.ssid]['pwd']
53
+ password = creds[args.ssid]['pwd'] # You'll need the password for Linux connections
60
54
 
61
- # displayAvailableNetworks()
62
- # createNewConnection(name, name, password)
55
+ # Create and connect to the network
56
+ create_new_connection(ssid, ssid, password)
63
57
  connect(ssid, ssid)
64
58
 
65
59
 
66
60
  def get_current_wifi_name() -> str:
67
- import subprocess
68
- import platform
69
61
  if platform.system() == "Windows":
70
62
  try:
71
63
  cmd_output = subprocess.check_output(["netsh", "wlan", "show", "interface"], shell=True).decode("utf-8")
@@ -28,7 +28,7 @@ Otherwise, a flag must be raised to indicate the direction.""")
28
28
  path = P(args.path).expanduser().absolute()
29
29
 
30
30
  if args.same_file_system:
31
- print(f"💥 Using a not recommended transfer method! Copying same files across different file systems.")
31
+ print("💥 Using a not recommended transfer method! Copying same files across different file systems.")
32
32
  if system == "Windows": # move files over to WSL
33
33
  path.copy(folder=WSL_FROM_WIN.joinpath(UserName).joinpath(path.rel2home().parent), overwrite=True) # the following works for files and folders alike.
34
34
  else: # move files from WSL to win
@@ -32,7 +32,7 @@ def install_nerd_fonts():
32
32
  folder.search("*readme*").apply(lambda p: p.delete(sure=True))
33
33
  folder.search("*LICENSE*").apply(lambda p: p.delete(sure=True))
34
34
  file = P.tmpfile(suffix=".ps1").write_text(LIBRARY_ROOT.joinpath("setup_windows/wt_and_pwsh/install_fonts.ps1").read_text().replace(r".\fonts-to-be-installed", str(folder)))
35
- subprocess.run(rf"powershell.exe -executionpolicy Bypass -nologo -noninteractive -File {file.str}", check=True)
35
+ subprocess.run(rf"powershell.exe -executionpolicy Bypass -nologo -noninteractive -File {file.to_str()}", check=True)
36
36
  folder.delete(sure=True)
37
37
 
38
38
 
@@ -52,7 +52,7 @@ class TerminalSettings(object):
52
52
 
53
53
  # 1- Customizing Powershell========================================================
54
54
  # as opposed to Windows Powershell
55
- def customize_powershell(self, nerd_font: bool = True):
55
+ def customize_powershell(self, nerd_font: bool=True):
56
56
  pwsh: dict[str, Any] = dict(name="PowerShell",
57
57
  commandline="pwsh",
58
58
  hidden=False,
@@ -65,7 +65,8 @@ class TerminalSettings(object):
65
65
  if item["name"] == "PowerShell":
66
66
  self.profs.list[idx].update(pwsh)
67
67
  break
68
- else: print(f"Couldn't customize powershell because profile not found, try to install it first.")
68
+ else:
69
+ print("Couldn't customize powershell because profile not found, try to install it first.")
69
70
 
70
71
  def make_powershell_default_profile(self):
71
72
  for profile in self.profs:
@@ -3,22 +3,23 @@
3
3
  """
4
4
  from rich.console import Console
5
5
 
6
- from crocodile.file_management import P, List as L, Read, Struct
6
+ from crocodile.file_management import P, List as L, Read
7
+ from crocodile.core import Struct
7
8
  from crocodile.meta import Terminal
8
9
  from machineconfig.utils.utils import INSTALL_VERSION_ROOT, INSTALL_TMP_DIR, LIBRARY_ROOT, check_tool_exists
9
10
 
10
11
  # from dataclasses import dataclass
11
- from typing import Optional, Any
12
+ from typing import Optional, Any, TypeAlias, Literal
12
13
  import platform
13
14
  # import os
14
15
 
15
16
 
16
17
  LINUX_INSTALL_PATH = '/usr/local/bin'
17
- WINDOWS_INSTALL_PATH = '~/AppData/Local/Microsoft/WindowsApps'
18
+ WINDOWS_INSTALL_PATH = P.home().joinpath("AppData/Local/Microsoft/WindowsApps").__str__()
19
+ CATEGORY: TypeAlias = Literal["OS_SPECIFIC", "OS_GENERIC", "CUSTOM", "OS_SPECIFIC_DEV", "OS_GENERIC_DEV", "CUSTOM_DEV"]
18
20
 
19
21
 
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}"""
22
+ def find_move_delete_windows(downloaded_file_path: P, exe_name: Optional[str] = None, delete: bool=True, rename_to: Optional[str] = None):
22
23
  if exe_name is not None and ".exe" in exe_name: exe_name = exe_name.replace(".exe", "")
23
24
  if downloaded_file_path.is_file():
24
25
  exe = downloaded_file_path
@@ -66,19 +67,20 @@ def find_move_delete_linux(downloaded: P, tool_name: str, delete: Optional[bool]
66
67
 
67
68
 
68
69
  class Installer:
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):
70
- self.repo_url = repo_url
71
- self.name = name
72
- self.doc = doc
73
- self.filename_template_windows_amd_64 = filename_template_windows_amd_64
74
- self.filename_template_linux_amd_64 = filename_template_linux_amd_64
75
- self.strip_v = strip_v
76
- self.exe_name = exe_name
70
+ def __init__(self, repo_url: str, name: str, doc: str, filename_template_windows_amd_64: str, filename_template_linux_amd_64: str,
71
+ strip_v: bool, exe_name: str):
72
+ self.repo_url: str=repo_url
73
+ self.name: str=name
74
+ self.doc: str=doc
75
+ self.filename_template_windows_amd_64: str=filename_template_windows_amd_64
76
+ self.filename_template_linux_amd_64: str=filename_template_linux_amd_64
77
+ self.strip_v: bool=strip_v
78
+ self.exe_name: str=exe_name
77
79
  def __repr__(self) -> str: return f"Installer of {self.repo_url}"
78
80
  def get_description(self):
79
81
  # old_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
80
82
  # old_version_cli = os.system(f"{self.exe_name} --version").replace("\n", "")
81
- old_version_cli = check_tool_exists(tool_name=self.exe_name)
83
+ old_version_cli: bool=check_tool_exists(tool_name=self.exe_name)
82
84
  old_version_cli_str = "✅" if old_version_cli else "❌"
83
85
  # name_version = f"{self.exe_name} {old_version_cli_str}"
84
86
  return f"{self.exe_name:<12} {old_version_cli_str} {self.doc}"
@@ -102,34 +104,41 @@ class Installer:
102
104
 
103
105
  def install_robust(self, version: Optional[str]):
104
106
  try:
107
+
105
108
  old_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
106
109
  self.install(version=version)
107
110
  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}"
111
+
112
+ if old_version_cli == new_version_cli: return f"""echo "📦️ 😑 {self.exe_name}, same version: {old_version_cli}" """
113
+ else: return f"""echo "📦️ 🤩 {self.exe_name} updated from {old_version_cli} === to ===> {new_version_cli}" """
114
+
110
115
  except Exception as ex:
111
116
  print(ex)
112
- return f"📦️ Failed at {self.exe_name} with {ex}"
117
+ return f"""echo "📦️ Failed at `{self.name}` with {ex}" """
113
118
 
114
119
  def install(self, version: Optional[str]):
115
120
  if self.repo_url == "CUSTOM":
121
+
116
122
  import machineconfig.jobs.python_custom_installers as python_custom_installers
117
123
  installer_path = P(python_custom_installers.__file__).parent.joinpath(self.exe_name + ".py")
124
+ if not installer_path.exists():
125
+ installer_path = P(python_custom_installers.__file__).parent.joinpath("dev", self.exe_name + ".py")
126
+
118
127
  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)
128
+ print(f"Executing func `main` from `{installer_path}`to get the program to run")
129
+ program: str=runpy.run_path(str(installer_path), run_name=None)['main'](version=version)
130
+ # print(program)
131
+ Terminal(stdin=None, stdout=None, stderr=None).run_script(script=program, shell="default").print(desc="Running custom installer", capture=True)
121
132
  # import subprocess
122
133
  # subprocess.run(program, shell=True, check=True)
123
134
  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"
135
+ elif "npm " in self.repo_url or "pip " in self.repo_url or "winget " in self.repo_url:
136
+ desc = self.repo_url.split(" ", maxsplit=1)[0] + "installation"
137
+ version_to_be_installed = self.repo_url.split(" ", maxsplit=1)[0] + "Latest"
138
+ Terminal().run(self.repo_url, shell="default").print_if_unsuccessful(desc=desc, strict_err=True, strict_returncode=True)
130
139
  else:
131
140
  downloaded, version_to_be_installed = self.download(version=version)
132
- if downloaded.str.endswith(".deb"):
141
+ if downloaded.to_str().endswith(".deb"):
133
142
  assert platform.system() == "Linux"
134
143
  Terminal().run(f"sudo apt install -y {downloaded}").print_if_unsuccessful(desc="Installing .deb", strict_err=True, strict_returncode=True)
135
144
  downloaded.delete(sure=True)
@@ -161,7 +170,7 @@ class Installer:
161
170
  else: raise NotImplementedError(f"📦️ System {platform.system()} not implemented")
162
171
  version_to_be_installed = "predefined_url"
163
172
  else:
164
- release_url, version_to_be_installed = self.get_github_release(repo_url=self.repo_url, version=version)
173
+ release_url, version_to_be_installed = Installer.get_github_release(repo_url=self.repo_url, version=version)
165
174
  print(f"📦️ Version to be installed: {version_to_be_installed}")
166
175
  print(f"📦️ Release URL: {release_url}")
167
176
  version_to_be_installed_stripped = version_to_be_installed.replace("v", "") if self.strip_v else version_to_be_installed
@@ -170,7 +179,7 @@ class Installer:
170
179
  elif platform.system() == "Linux":
171
180
  file_name = self.filename_template_linux_amd_64.format(version_to_be_installed_stripped)
172
181
  else: raise NotImplementedError(f"📦️ System {platform.system()} not implemented")
173
- print(f"📦️ File name", file_name)
182
+ print("📦️ File name", file_name)
174
183
  download_link = release_url.joinpath(file_name)
175
184
  print(f"📦️ Downloading {self.name}: ", download_link.as_url_str())
176
185
  downloaded = download_link.download(folder=INSTALL_TMP_DIR).decompress()
@@ -262,36 +271,66 @@ def get_installed_cli_apps():
262
271
 
263
272
 
264
273
  def get_installers(system: str, dev: bool) -> list[Installer]:
274
+ res_all = get_all_dicts(system=system)
275
+ if not dev:
276
+ del res_all["CUSTOM_DEV"]
277
+ del res_all["OS_SPECIFIC_DEV"]
278
+ del res_all["OS_GENERIC_DEV"]
279
+ res_final = {}
280
+ for _k, v in res_all.items():
281
+ res_final.update(v)
282
+ return [Installer.from_dict(d=vd, name=k) for k, vd in res_final.items()]
283
+
284
+
285
+ def get_all_dicts(system: str) -> dict[CATEGORY, dict[str, dict[str, Any]]]:
265
286
  if system == "Windows": import machineconfig.jobs.python_windows_installers as os_specific_installer
266
287
  else: import machineconfig.jobs.python_linux_installers as os_specific_installer
288
+
267
289
  import machineconfig.jobs.python_generic_installers as generic_installer
268
290
  path_os_specific = P(os_specific_installer.__file__).parent
269
291
  path_os_generic = P(generic_installer.__file__).parent
292
+
293
+ path_os_specific_dev = path_os_specific.joinpath("dev")
294
+ path_os_generic_dev = path_os_generic.joinpath("dev")
295
+
296
+ res_final: dict[CATEGORY, dict[str, dict[str, Any]]] = {}
297
+ res_final["OS_SPECIFIC"] = Read.json(path=path_os_specific.joinpath("config.json"))
298
+ res_final["OS_GENERIC"] = Read.json(path=path_os_generic.joinpath("config.json"))
299
+ res_final["OS_SPECIFIC_DEV"] = Read.json(path=path_os_specific_dev.joinpath("config.json"))
300
+ res_final["OS_GENERIC_DEV"] = Read.json(path=path_os_generic_dev.joinpath("config.json"))
301
+
270
302
  path_custom_installer = path_os_generic.with_name("python_custom_installers")
271
- if dev:
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"))
276
- res2.update(res1)
303
+ path_custom_installer_dev = path_custom_installer.joinpath("dev")
304
+
277
305
  import runpy
278
- for item in path_custom_installer.search("*.py", r=False):
306
+ res_custom: dict[str, dict[str, Any]] = {}
307
+ for item in path_custom_installer.search("*.py", r=False, not_in=["__init__"]):
308
+ try:
309
+ config_dict = runpy.run_path(str(item), run_name=None)['config_dict']
310
+ res_custom[item.stem] = config_dict
311
+ except Exception as ex:
312
+ print(f"Failed to load {item}: {ex}")
313
+
314
+ res_custom_dev: dict[str, dict[str, Any]] = {}
315
+ for item in path_custom_installer_dev.search("*.py", r=False, not_in=["__init__"]):
279
316
  try:
280
317
  config_dict = runpy.run_path(str(item), run_name=None)['config_dict']
281
- res2[item.stem] = config_dict
318
+ res_custom_dev[item.stem] = config_dict
282
319
  except Exception as ex:
283
320
  print(f"Failed to load {item}: {ex}")
284
321
 
285
- return [Installer.from_dict(d=vd, name=k) for k, vd in res2.items()]
322
+ res_final["CUSTOM"] = res_custom
323
+ res_final["CUSTOM_DEV"] = res_custom_dev
324
+ return res_final
286
325
 
287
326
 
288
- def install_all(installers: L[Installer], safe: bool = False, jobs: int = 10, fresh: bool = False):
327
+ def install_all(installers: L[Installer], safe: bool=False, jobs: int = 10, fresh: bool=False):
289
328
  if fresh: INSTALL_VERSION_ROOT.delete(sure=True)
290
329
  if safe:
291
330
  from machineconfig.jobs.python.check_installations import APP_SUMMARY_PATH
292
331
  apps_dir = APP_SUMMARY_PATH.readit()
293
332
  if platform.system().lower() == "windows":
294
- apps_dir.search("*").apply(lambda app: app.move(folder=P.get_env().WindowsApps))
333
+ apps_dir.search("*").apply(lambda app: app.move(folder=P.get_env().WindowsPaths().WindowsApps))
295
334
  elif platform.system().lower() == "linux":
296
335
  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)
297
336
  else: raise NotImplementedError(f"I don't know this system {platform.system()}")
@@ -60,7 +60,7 @@ class ProcessManager:
60
60
  self.kill(pids=sub_df.pid.to_list())
61
61
  return
62
62
  kill_by_index = input("🔫 Kill by index? 1 4 ... /[n] ")
63
- if kill_by_index != "":
63
+ if kill_by_index != "" and kill_by_index != "n":
64
64
  indices = [int(val) for val in kill_by_index.split(" ")]
65
65
  sub_sub_df = sub_df.iloc[indices]
66
66
  for idx2, row in sub_sub_df.iterrows():
@@ -93,7 +93,7 @@ class ProcessManager:
93
93
  print(f'💀 Killed process with pid {pid} and name {proc.name()}. It lived {get_age(proc.create_time())}. RIP 🪦💐')
94
94
  except psutil.NoSuchProcess: print(f'No process with pid {pid} found')
95
95
  for command in commands:
96
- rows = self.df[self.df['command'].str.contains(command)]
96
+ rows = self.df[self.df['command'].to_str().contains(command)]
97
97
  if len(rows) > 0:
98
98
  for _idx, a_row in rows.iterrows():
99
99
  psutil.Process(a_row.pid).kill()
@@ -62,7 +62,7 @@ class Report:
62
62
  status: str
63
63
 
64
64
  @classmethod
65
- def from_path(cls, path: P, return_default_if_not_found: bool = False):
65
+ def from_path(cls, path: P, return_default_if_not_found: bool=False):
66
66
  if not path.exists():
67
67
  if return_default_if_not_found:
68
68
  return Report(name=path.parent.name, start=datetime(year=2000, month=1, day=1), end=datetime(year=2000, month=1, day=1), status="NA")
@@ -108,7 +108,7 @@ def read_task_from_dir(path: P):
108
108
  return task
109
109
 
110
110
 
111
- def main(root: Optional[str] = None, ignore_conditions: bool = True):
111
+ def main(root: Optional[str] = None, ignore_conditions: bool=True):
112
112
  if root is None: root_resolved = SCHEDULER_DEFAULT_ROOT
113
113
  else: root_resolved = P(root).expanduser().absolute()
114
114
  tasks_dirs = root_resolved.search(files=False, folders=True).filter(lambda x: x.joinpath("task.py").exists())
@@ -168,7 +168,7 @@ def should_task_run(task: Task, tolerance_mins: int = 1440) -> tuple[bool, Optio
168
168
  def run_task(task: Task) -> Report:
169
169
  start_time = datetime.now()
170
170
 
171
- shell_script = get_shell_script_executing_python_file(python_file=task.task_root.joinpath("task.py").str, ve_name=task.venv)
171
+ shell_script = get_shell_script_executing_python_file(python_file=task.task_root.joinpath("task.py").to_str(), ve_name=task.venv)
172
172
  shell_script_root = P.tmp().joinpath(f"tmp_scripts/scheduler/{task.name}").create()
173
173
  try:
174
174
  if platform.system() == 'Windows':