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.
- machineconfig/__init__.py +1 -1
- machineconfig/jobs/python/check_installations.py +7 -5
- machineconfig/jobs/python/checkout_version.py +27 -32
- machineconfig/jobs/python/create_bootable_media.py +1 -1
- machineconfig/jobs/python/python_cargo_build_share.py +2 -2
- machineconfig/jobs/python/tasks.py +2 -2
- machineconfig/jobs/python_custom_installers/{helix.py → hx.py} +17 -5
- machineconfig/profile/create.py +23 -21
- machineconfig/profile/create_hardlinks.py +101 -0
- machineconfig/profile/shell.py +5 -5
- machineconfig/scripts/python/cloud_copy.py +19 -16
- machineconfig/scripts/python/cloud_repo_sync.py +92 -47
- machineconfig/scripts/python/cloud_sync.py +70 -63
- machineconfig/scripts/python/croshell.py +6 -6
- machineconfig/scripts/python/devops.py +19 -20
- machineconfig/scripts/python/devops_backup_retrieve.py +19 -10
- machineconfig/scripts/python/devops_devapps_install.py +80 -62
- machineconfig/scripts/python/devops_update_repos.py +5 -5
- machineconfig/scripts/python/dotfile.py +4 -4
- machineconfig/scripts/python/fire_jobs.py +57 -23
- machineconfig/scripts/python/gh_models.py +53 -0
- machineconfig/scripts/python/mount_nfs.py +1 -1
- machineconfig/scripts/python/mount_nw_drive.py +3 -3
- machineconfig/scripts/python/mount_ssh.py +2 -3
- machineconfig/scripts/python/pomodoro.py +1 -1
- machineconfig/scripts/python/repos.py +21 -22
- machineconfig/scripts/python/scheduler.py +1 -1
- machineconfig/scripts/python/start_slidev.py +10 -4
- machineconfig/scripts/python/start_terminals.py +5 -4
- machineconfig/scripts/python/wifi_conn.py +34 -42
- machineconfig/scripts/python/wsl_windows_transfer.py +1 -1
- machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +1 -1
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +3 -2
- machineconfig/utils/installer.py +78 -39
- machineconfig/utils/procs.py +2 -2
- machineconfig/utils/scheduling.py +3 -3
- machineconfig/utils/utils.py +131 -52
- machineconfig/utils/ve.py +145 -95
- {machineconfig-1.9.dist-info → machineconfig-1.91.dist-info}/METADATA +160 -155
- machineconfig-1.91.dist-info/RECORD +69 -0
- machineconfig/jobs/python_custom_installers/azuredatastudio.py +0 -36
- machineconfig/jobs/python_custom_installers/bypass_paywall.py +0 -30
- machineconfig/jobs/python_custom_installers/docker_desktop.py +0 -52
- machineconfig/jobs/python_custom_installers/goes.py +0 -35
- machineconfig/jobs/python_custom_installers/lvim.py +0 -48
- machineconfig/jobs/python_custom_installers/ngrok.py +0 -39
- machineconfig/jobs/python_custom_installers/nvim.py +0 -48
- machineconfig/jobs/python_custom_installers/vscode.py +0 -45
- machineconfig/jobs/python_custom_installers/wezterm.py +0 -41
- machineconfig-1.9.dist-info/RECORD +0 -76
- {machineconfig-1.9.dist-info → machineconfig-1.91.dist-info}/LICENSE +0 -0
- {machineconfig-1.9.dist-info → machineconfig-1.91.dist-info}/WHEEL +0 -0
- {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.
|
|
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
|
-
|
|
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,
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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=
|
|
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
|
-
|
|
53
|
+
password = creds[args.ssid]['pwd'] # You'll need the password for Linux connections
|
|
60
54
|
|
|
61
|
-
#
|
|
62
|
-
|
|
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(
|
|
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.
|
|
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
|
|
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:
|
|
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:
|
machineconfig/utils/installer.py
CHANGED
|
@@ -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
|
|
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 =
|
|
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
|
|
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,
|
|
70
|
-
|
|
71
|
-
self.
|
|
72
|
-
self.
|
|
73
|
-
self.
|
|
74
|
-
self.
|
|
75
|
-
self.
|
|
76
|
-
self.
|
|
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 =
|
|
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
|
-
|
|
109
|
-
|
|
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.
|
|
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
|
-
|
|
120
|
-
|
|
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
|
-
|
|
126
|
-
version_to_be_installed = "
|
|
127
|
-
|
|
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.
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
272
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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()}")
|
machineconfig/utils/procs.py
CHANGED
|
@@ -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'].
|
|
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
|
|
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
|
|
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").
|
|
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':
|