machineconfig 1.9__py3-none-any.whl → 1.92__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 +2 -4
- machineconfig/jobs/python/check_installations.py +14 -6
- 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} +21 -6
- machineconfig/profile/create.py +23 -21
- machineconfig/profile/create_hardlinks.py +101 -0
- machineconfig/profile/shell.py +10 -7
- machineconfig/scripts/python/cloud_copy.py +19 -16
- machineconfig/scripts/python/cloud_repo_sync.py +94 -47
- machineconfig/scripts/python/cloud_sync.py +78 -61
- machineconfig/scripts/python/croshell.py +6 -6
- machineconfig/scripts/python/devops.py +22 -22
- machineconfig/scripts/python/devops_add_ssh_key.py +1 -1
- 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 +115 -63
- machineconfig/scripts/python/gh_models.py +55 -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 +22 -23
- machineconfig/scripts/python/scheduler.py +1 -1
- machineconfig/scripts/python/start_slidev.py +12 -6
- 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/settings/__init__.py +0 -0
- 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 +86 -41
- machineconfig/utils/procs.py +2 -2
- machineconfig/utils/scheduling.py +3 -3
- machineconfig/utils/utils.py +136 -56
- machineconfig/utils/ve.py +145 -95
- {machineconfig-1.9.dist-info → machineconfig-1.92.dist-info}/METADATA +160 -155
- machineconfig-1.92.dist-info/RECORD +70 -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.92.dist-info}/LICENSE +0 -0
- {machineconfig-1.9.dist-info → machineconfig-1.92.dist-info}/WHEEL +0 -0
- {machineconfig-1.9.dist-info → machineconfig-1.92.dist-info}/top_level.txt +0 -0
|
@@ -16,7 +16,7 @@ def pomodoro(work: int = 25, rest: int = 5, repeats: int = 4):
|
|
|
16
16
|
while (diff := rest - ((datetime.now() - start).seconds / 60)) > 0: logger.critical(f"Keep Resting. Time Left: {round(diff)} minutes"); time.sleep(60 * 1)
|
|
17
17
|
def speak(txt: str):
|
|
18
18
|
install_n_import("gtts").gTTS(txt, lang='en', tld='com.au').save(tmp := P.tmpfile(suffix=".mp3")); time.sleep(0.5)
|
|
19
|
-
pyglet = install_n_import("pyglet"); pyglet.resource.path = [tmp.parent.
|
|
19
|
+
pyglet = install_n_import("pyglet"); pyglet.resource.path = [tmp.parent.to_str()]; pyglet.resource.reindex(); pyglet.resource.media(tmp.name).play()
|
|
20
20
|
def beep(duration: int = 1, frequency: int = 3000):
|
|
21
21
|
try: import winsound
|
|
22
22
|
except ImportError: __import__("os").system(f'beep -f {frequency} -l {1000 * duration}')
|
|
@@ -8,7 +8,7 @@ in the event that username@github.com is not mentioned in the remote url.
|
|
|
8
8
|
|
|
9
9
|
from rich import print as pprint
|
|
10
10
|
from machineconfig.utils.utils import write_shell_script, CONFIG_PATH, DEFAULTS_PATH
|
|
11
|
-
from crocodile.file_management import P,
|
|
11
|
+
from crocodile.file_management import P, Read, Save
|
|
12
12
|
from crocodile.core import randstr
|
|
13
13
|
import argparse
|
|
14
14
|
from dataclasses import dataclass
|
|
@@ -31,7 +31,7 @@ class RepoRecord:
|
|
|
31
31
|
version: dict[str, str]
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
def git_action(path: P, action: GitAction, mess: Optional[str] = None, r: bool
|
|
34
|
+
def git_action(path: P, action: GitAction, mess: Optional[str] = None, r: bool=False) -> str:
|
|
35
35
|
from git.exc import InvalidGitRepositoryError
|
|
36
36
|
from git.repo import Repo
|
|
37
37
|
try:
|
|
@@ -57,7 +57,7 @@ git add .; git commit -am "{mess}"
|
|
|
57
57
|
action_name = "pull" if action == GitAction.pull else "push"
|
|
58
58
|
cmds = [f'echo "pulling from {remote.url}" ; git {action_name} {remote.name} {repo.active_branch.name}' for remote in repo.remotes]
|
|
59
59
|
program += '\n' + '\n'.join(cmds) + '\n'
|
|
60
|
-
program = program +
|
|
60
|
+
program = program + '''
|
|
61
61
|
echo ""; echo ""
|
|
62
62
|
'''
|
|
63
63
|
return program
|
|
@@ -68,41 +68,40 @@ def main():
|
|
|
68
68
|
# POSITIONAL
|
|
69
69
|
parser.add_argument("directory", help="folder containing repos to record a json out of OR a specs json file to follow.", default="")
|
|
70
70
|
# FLAGS
|
|
71
|
-
parser.add_argument("--push", help=
|
|
72
|
-
parser.add_argument("--pull", help=
|
|
73
|
-
parser.add_argument("--commit", help=
|
|
74
|
-
parser.add_argument("--all", help=
|
|
75
|
-
parser.add_argument("--record", help=
|
|
76
|
-
parser.add_argument("--clone", help=
|
|
77
|
-
parser.add_argument("--checkout", help=
|
|
71
|
+
parser.add_argument("--push", help="push", action="store_true")
|
|
72
|
+
parser.add_argument("--pull", help="pull", action="store_true")
|
|
73
|
+
parser.add_argument("--commit", help="commit", action="store_true")
|
|
74
|
+
parser.add_argument("--all", help="pull, commit and push", action="store_true")
|
|
75
|
+
parser.add_argument("--record", help="record respos", action="store_true")
|
|
76
|
+
parser.add_argument("--clone", help="clone repos from record", action="store_true")
|
|
77
|
+
parser.add_argument("--checkout", help="Check out to versions prvided in this json file", action="store_true")
|
|
78
78
|
parser.add_argument("--checkout_to_branch", help="Checkout to the main branch", action="store_true")
|
|
79
|
-
parser.add_argument("--recursive", "-r", help=
|
|
79
|
+
parser.add_argument("--recursive", "-r", help="recursive flag", action="store_true")
|
|
80
80
|
# OPTIONAL
|
|
81
|
-
parser.add_argument("--cloud", "-c", help=
|
|
81
|
+
parser.add_argument("--cloud", "-c", help="cloud", default=None)
|
|
82
82
|
args = parser.parse_args()
|
|
83
83
|
|
|
84
84
|
if args.directory == "": repos_root = P.home().joinpath("code") # it is a positional argument, can never be empty.
|
|
85
85
|
else: repos_root = P(args.directory).expanduser().absolute()
|
|
86
|
-
_ = install_n_import("git", "gitpython")
|
|
87
86
|
|
|
88
87
|
program = ""
|
|
89
88
|
if args.record:
|
|
90
89
|
res = record_repos(repos_root=str(repos_root))
|
|
91
|
-
pprint(
|
|
90
|
+
pprint("Recorded repositories:\n", res)
|
|
92
91
|
save_path = CONFIG_PATH.joinpath("repos").joinpath(repos_root.rel2home()).joinpath("repos.json")
|
|
93
92
|
# Save.pickle(obj=res, path=save_path)
|
|
94
|
-
Save.json(obj=res, path=save_path)
|
|
93
|
+
Save.json(obj=res, path=save_path, indent=4)
|
|
95
94
|
pprint(f"Result pickled at {P(save_path)}")
|
|
96
95
|
if args.cloud is not None: P(save_path).to_cloud(rel2home=True, cloud=args.cloud)
|
|
97
|
-
program +=
|
|
96
|
+
program += """\necho '>>>>>>>>> Finished Recording'\n"""
|
|
98
97
|
elif args.clone or args.checkout or args.checkout_to_branch:
|
|
99
98
|
# preferred_remote = input("Enter preferred remote to use (default: None): ") or ""
|
|
100
|
-
program +=
|
|
99
|
+
program += """\necho '>>>>>>>>> Cloning Repos'\n"""
|
|
101
100
|
if not repos_root.exists() or repos_root.stem != 'repos.json': # user didn't pass absolute path to pickle file, but rather expected it to be in the default save location
|
|
102
101
|
repos_root = CONFIG_PATH.joinpath("repos").joinpath(repos_root.rel2home()).joinpath("repos.json")
|
|
103
102
|
if not repos_root.exists():
|
|
104
103
|
if args.cloud is None:
|
|
105
|
-
cloud: str
|
|
104
|
+
cloud: str=Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
|
|
106
105
|
print(f"⚠️ Using default cloud: {cloud}")
|
|
107
106
|
else:
|
|
108
107
|
cloud = args.cloud
|
|
@@ -119,10 +118,10 @@ def main():
|
|
|
119
118
|
if args.commit or args.all: program += git_action(a_path, action=GitAction.commit, r=args.recursive)
|
|
120
119
|
if args.push or args.all: program += git_action(a_path, action=GitAction.push, r=args.recursive)
|
|
121
120
|
else: program = "echo 'no action specified, try to pass --push, --pull, --commit or --all'"
|
|
122
|
-
write_shell_script(program, "Script to update repos")
|
|
121
|
+
write_shell_script(program=program, desc="Script to update repos", preserve_cwd=True)
|
|
123
122
|
|
|
124
123
|
|
|
125
|
-
def record_repos(repos_root: str, r: bool
|
|
124
|
+
def record_repos(repos_root: str, r: bool=True) -> list[dict[str, Any]]:
|
|
126
125
|
path_obj = P(repos_root).expanduser().absolute()
|
|
127
126
|
if path_obj.is_file(): return []
|
|
128
127
|
search_res = path_obj.search("*", files=False)
|
|
@@ -135,7 +134,7 @@ def record_repos(repos_root: str, r: bool = True) -> list[dict[str, Any]]:
|
|
|
135
134
|
return res
|
|
136
135
|
|
|
137
136
|
|
|
138
|
-
def record_a_repo(path: P, search_parent_directories: bool
|
|
137
|
+
def record_a_repo(path: P, search_parent_directories: bool=False, preferred_remote: Optional[str] = None):
|
|
139
138
|
from git.repo import Repo
|
|
140
139
|
repo = Repo(path, search_parent_directories=search_parent_directories) # get list of remotes using git python
|
|
141
140
|
repo_root = P(repo.working_dir).absolute()
|
|
@@ -160,7 +159,7 @@ def record_a_repo(path: P, search_parent_directories: bool = False, preferred_re
|
|
|
160
159
|
return res
|
|
161
160
|
|
|
162
161
|
|
|
163
|
-
def install_repos(specs_path: str, clone: bool
|
|
162
|
+
def install_repos(specs_path: str, clone: bool=True, checkout_to_recorded_commit: bool=False, checkout_to_branch: bool=False, editable_install: bool=False, preferred_remote: Optional[str] = None):
|
|
164
163
|
program = ""
|
|
165
164
|
path_obj = P(specs_path).expanduser().absolute()
|
|
166
165
|
repos: list[dict[str, Any]] = Read.json(path_obj)
|
|
@@ -189,7 +188,7 @@ def install_repos(specs_path: str, clone: bool = True, checkout_to_recorded_comm
|
|
|
189
188
|
program += f"\ncd {parent_dir.collapseuser().as_posix()}/{repo['name']}; git checkout {repo['current_branch']}"
|
|
190
189
|
break
|
|
191
190
|
if editable_install and idx == 0:
|
|
192
|
-
program += f"\ncd {parent_dir.collapseuser().as_posix()}/{repo['name']}; pip install -e ."
|
|
191
|
+
program += f"\ncd {parent_dir.collapseuser().as_posix()}/{repo['name']}; uv pip install -e ."
|
|
193
192
|
program += "\n"
|
|
194
193
|
pprint(program)
|
|
195
194
|
return program
|
|
@@ -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))
|
|
@@ -89,15 +90,20 @@ def main() -> None:
|
|
|
89
90
|
import socket
|
|
90
91
|
try: local_ip_v4 = socket.gethostbyname(socket.gethostname() + ".local") # without .local, in linux machines, '/etc/hosts' file content, you have an IP address mapping with '127.0.1.1' to your hostname
|
|
91
92
|
except Exception:
|
|
92
|
-
print(
|
|
93
|
+
print("Warning: Could not get local_ip_v4. This is probably because you are running a WSL instance") # TODO find a way to get the local_ip_v4 in WSL
|
|
93
94
|
local_ip_v4 = socket.gethostbyname(socket.gethostname())
|
|
94
95
|
|
|
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
|
-
print_code(program, lexer="bash")
|
|
106
|
+
print_code(code=program, lexer="bash", desc="Run the following command to start the presentation")
|
|
101
107
|
|
|
102
108
|
|
|
103
109
|
if __name__ == '__main__':
|
|
@@ -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
|
|
File without changes
|
|
@@ -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,25 @@
|
|
|
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
|
-
LINUX_INSTALL_PATH = '/usr/local/bin'
|
|
17
|
-
|
|
17
|
+
# LINUX_INSTALL_PATH = '/usr/local/bin'
|
|
18
|
+
LINUX_INSTALL_PATH = '~/.local/bin'
|
|
18
19
|
|
|
20
|
+
WINDOWS_INSTALL_PATH = P.home().joinpath("AppData/Local/Microsoft/WindowsApps").__str__()
|
|
21
|
+
CATEGORY: TypeAlias = Literal["OS_SPECIFIC", "OS_GENERIC", "CUSTOM", "OS_SPECIFIC_DEV", "OS_GENERIC_DEV", "CUSTOM_DEV"]
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
|
|
24
|
+
def find_move_delete_windows(downloaded_file_path: P, exe_name: Optional[str] = None, delete: bool=True, rename_to: Optional[str] = None):
|
|
22
25
|
if exe_name is not None and ".exe" in exe_name: exe_name = exe_name.replace(".exe", "")
|
|
23
26
|
if downloaded_file_path.is_file():
|
|
24
27
|
exe = downloaded_file_path
|
|
@@ -59,26 +62,30 @@ def find_move_delete_linux(downloaded: P, tool_name: str, delete: Optional[bool]
|
|
|
59
62
|
print(f"MOVING file `{repr(exe)}` to '{LINUX_INSTALL_PATH}'")
|
|
60
63
|
exe.chmod(0o777)
|
|
61
64
|
# exe.move(folder=LINUX_INSTALL_PATH, overwrite=False)
|
|
62
|
-
|
|
65
|
+
if "/usr" in LINUX_INSTALL_PATH:
|
|
66
|
+
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)
|
|
67
|
+
else:
|
|
68
|
+
exe.move(folder=LINUX_INSTALL_PATH, overwrite=True)
|
|
63
69
|
if delete: downloaded.delete(sure=True)
|
|
64
70
|
exe_new_location = P(LINUX_INSTALL_PATH).joinpath(exe.name)
|
|
65
71
|
return exe_new_location
|
|
66
72
|
|
|
67
73
|
|
|
68
74
|
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.
|
|
75
|
+
def __init__(self, repo_url: str, name: str, doc: str, filename_template_windows_amd_64: str, filename_template_linux_amd_64: str,
|
|
76
|
+
strip_v: bool, exe_name: str):
|
|
77
|
+
self.repo_url: str=repo_url
|
|
78
|
+
self.name: str=name
|
|
79
|
+
self.doc: str=doc
|
|
80
|
+
self.filename_template_windows_amd_64: str=filename_template_windows_amd_64
|
|
81
|
+
self.filename_template_linux_amd_64: str=filename_template_linux_amd_64
|
|
82
|
+
self.strip_v: bool=strip_v
|
|
83
|
+
self.exe_name: str=exe_name
|
|
77
84
|
def __repr__(self) -> str: return f"Installer of {self.repo_url}"
|
|
78
85
|
def get_description(self):
|
|
79
86
|
# old_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
|
|
80
87
|
# old_version_cli = os.system(f"{self.exe_name} --version").replace("\n", "")
|
|
81
|
-
old_version_cli =
|
|
88
|
+
old_version_cli: bool=check_tool_exists(tool_name=self.exe_name)
|
|
82
89
|
old_version_cli_str = "✅" if old_version_cli else "❌"
|
|
83
90
|
# name_version = f"{self.exe_name} {old_version_cli_str}"
|
|
84
91
|
return f"{self.exe_name:<12} {old_version_cli_str} {self.doc}"
|
|
@@ -102,34 +109,41 @@ class Installer:
|
|
|
102
109
|
|
|
103
110
|
def install_robust(self, version: Optional[str]):
|
|
104
111
|
try:
|
|
112
|
+
|
|
105
113
|
old_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
|
|
106
114
|
self.install(version=version)
|
|
107
115
|
new_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
|
|
117
|
+
if old_version_cli == new_version_cli: return f"""echo "📦️ 😑 {self.exe_name}, same version: {old_version_cli}" """
|
|
118
|
+
else: return f"""echo "📦️ 🤩 {self.exe_name} updated from {old_version_cli} ➡️ TO ➡️ {new_version_cli}" """
|
|
119
|
+
|
|
110
120
|
except Exception as ex:
|
|
111
121
|
print(ex)
|
|
112
|
-
return f"📦️ Failed at {self.
|
|
122
|
+
return f"""echo "📦️ Failed at `{self.name}` with {ex}" """
|
|
113
123
|
|
|
114
124
|
def install(self, version: Optional[str]):
|
|
115
125
|
if self.repo_url == "CUSTOM":
|
|
126
|
+
|
|
116
127
|
import machineconfig.jobs.python_custom_installers as python_custom_installers
|
|
117
128
|
installer_path = P(python_custom_installers.__file__).parent.joinpath(self.exe_name + ".py")
|
|
129
|
+
if not installer_path.exists():
|
|
130
|
+
installer_path = P(python_custom_installers.__file__).parent.joinpath("dev", self.exe_name + ".py")
|
|
131
|
+
|
|
118
132
|
import runpy
|
|
119
|
-
|
|
120
|
-
|
|
133
|
+
print(f"Executing func `main` from `{installer_path}`to get the program to run")
|
|
134
|
+
program: str = runpy.run_path(str(installer_path), run_name=None)['main'](version=version)
|
|
135
|
+
# print(program)
|
|
136
|
+
Terminal(stdin=None, stdout=None, stderr=None).run_script(script=program, shell="default").print(desc="Running custom installer", capture=True)
|
|
121
137
|
# import subprocess
|
|
122
138
|
# subprocess.run(program, shell=True, check=True)
|
|
123
139
|
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"
|
|
140
|
+
elif "npm " in self.repo_url or "pip " in self.repo_url or "winget " in self.repo_url:
|
|
141
|
+
desc = self.repo_url.split(" ", maxsplit=1)[0] + "installation"
|
|
142
|
+
version_to_be_installed = self.repo_url.split(" ", maxsplit=1)[0] + "Latest"
|
|
143
|
+
Terminal().run(self.repo_url, shell="default").print_if_unsuccessful(desc=desc, strict_err=True, strict_returncode=True)
|
|
130
144
|
else:
|
|
131
145
|
downloaded, version_to_be_installed = self.download(version=version)
|
|
132
|
-
if downloaded.
|
|
146
|
+
if downloaded.to_str().endswith(".deb"):
|
|
133
147
|
assert platform.system() == "Linux"
|
|
134
148
|
Terminal().run(f"sudo apt install -y {downloaded}").print_if_unsuccessful(desc="Installing .deb", strict_err=True, strict_returncode=True)
|
|
135
149
|
downloaded.delete(sure=True)
|
|
@@ -161,16 +175,17 @@ class Installer:
|
|
|
161
175
|
else: raise NotImplementedError(f"📦️ System {platform.system()} not implemented")
|
|
162
176
|
version_to_be_installed = "predefined_url"
|
|
163
177
|
else:
|
|
164
|
-
release_url, version_to_be_installed =
|
|
178
|
+
release_url, version_to_be_installed = Installer.get_github_release(repo_url=self.repo_url, version=version)
|
|
165
179
|
print(f"📦️ Version to be installed: {version_to_be_installed}")
|
|
166
180
|
print(f"📦️ Release URL: {release_url}")
|
|
167
181
|
version_to_be_installed_stripped = version_to_be_installed.replace("v", "") if self.strip_v else version_to_be_installed
|
|
182
|
+
version_to_be_installed_stripped = version_to_be_installed_stripped.replace("ipinfo-", "")
|
|
168
183
|
if platform.system() == "Windows":
|
|
169
184
|
file_name = self.filename_template_windows_amd_64.format(version_to_be_installed_stripped)
|
|
170
185
|
elif platform.system() == "Linux":
|
|
171
186
|
file_name = self.filename_template_linux_amd_64.format(version_to_be_installed_stripped)
|
|
172
187
|
else: raise NotImplementedError(f"📦️ System {platform.system()} not implemented")
|
|
173
|
-
print(
|
|
188
|
+
print("📦️ File name", file_name)
|
|
174
189
|
download_link = release_url.joinpath(file_name)
|
|
175
190
|
print(f"📦️ Downloading {self.name}: ", download_link.as_url_str())
|
|
176
191
|
downloaded = download_link.download(folder=INSTALL_TMP_DIR).decompress()
|
|
@@ -262,36 +277,66 @@ def get_installed_cli_apps():
|
|
|
262
277
|
|
|
263
278
|
|
|
264
279
|
def get_installers(system: str, dev: bool) -> list[Installer]:
|
|
280
|
+
res_all = get_all_dicts(system=system)
|
|
281
|
+
if not dev:
|
|
282
|
+
del res_all["CUSTOM_DEV"]
|
|
283
|
+
del res_all["OS_SPECIFIC_DEV"]
|
|
284
|
+
del res_all["OS_GENERIC_DEV"]
|
|
285
|
+
res_final = {}
|
|
286
|
+
for _k, v in res_all.items():
|
|
287
|
+
res_final.update(v)
|
|
288
|
+
return [Installer.from_dict(d=vd, name=k) for k, vd in res_final.items()]
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def get_all_dicts(system: str) -> dict[CATEGORY, dict[str, dict[str, Any]]]:
|
|
265
292
|
if system == "Windows": import machineconfig.jobs.python_windows_installers as os_specific_installer
|
|
266
293
|
else: import machineconfig.jobs.python_linux_installers as os_specific_installer
|
|
294
|
+
|
|
267
295
|
import machineconfig.jobs.python_generic_installers as generic_installer
|
|
268
296
|
path_os_specific = P(os_specific_installer.__file__).parent
|
|
269
297
|
path_os_generic = P(generic_installer.__file__).parent
|
|
298
|
+
|
|
299
|
+
path_os_specific_dev = path_os_specific.joinpath("dev")
|
|
300
|
+
path_os_generic_dev = path_os_generic.joinpath("dev")
|
|
301
|
+
|
|
302
|
+
res_final: dict[CATEGORY, dict[str, dict[str, Any]]] = {}
|
|
303
|
+
res_final["OS_SPECIFIC"] = Read.json(path=path_os_specific.joinpath("config.json"))
|
|
304
|
+
res_final["OS_GENERIC"] = Read.json(path=path_os_generic.joinpath("config.json"))
|
|
305
|
+
res_final["OS_SPECIFIC_DEV"] = Read.json(path=path_os_specific_dev.joinpath("config.json"))
|
|
306
|
+
res_final["OS_GENERIC_DEV"] = Read.json(path=path_os_generic_dev.joinpath("config.json"))
|
|
307
|
+
|
|
270
308
|
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)
|
|
309
|
+
path_custom_installer_dev = path_custom_installer.joinpath("dev")
|
|
310
|
+
|
|
277
311
|
import runpy
|
|
278
|
-
|
|
312
|
+
res_custom: dict[str, dict[str, Any]] = {}
|
|
313
|
+
for item in path_custom_installer.search("*.py", r=False, not_in=["__init__"]):
|
|
314
|
+
try:
|
|
315
|
+
config_dict = runpy.run_path(str(item), run_name=None)['config_dict']
|
|
316
|
+
res_custom[item.stem] = config_dict
|
|
317
|
+
except Exception as ex:
|
|
318
|
+
print(f"Failed to load {item}: {ex}")
|
|
319
|
+
|
|
320
|
+
res_custom_dev: dict[str, dict[str, Any]] = {}
|
|
321
|
+
for item in path_custom_installer_dev.search("*.py", r=False, not_in=["__init__"]):
|
|
279
322
|
try:
|
|
280
323
|
config_dict = runpy.run_path(str(item), run_name=None)['config_dict']
|
|
281
|
-
|
|
324
|
+
res_custom_dev[item.stem] = config_dict
|
|
282
325
|
except Exception as ex:
|
|
283
326
|
print(f"Failed to load {item}: {ex}")
|
|
284
327
|
|
|
285
|
-
|
|
328
|
+
res_final["CUSTOM"] = res_custom
|
|
329
|
+
res_final["CUSTOM_DEV"] = res_custom_dev
|
|
330
|
+
return res_final
|
|
286
331
|
|
|
287
332
|
|
|
288
|
-
def install_all(installers: L[Installer], safe: bool
|
|
333
|
+
def install_all(installers: L[Installer], safe: bool=False, jobs: int = 10, fresh: bool=False):
|
|
289
334
|
if fresh: INSTALL_VERSION_ROOT.delete(sure=True)
|
|
290
335
|
if safe:
|
|
291
336
|
from machineconfig.jobs.python.check_installations import APP_SUMMARY_PATH
|
|
292
337
|
apps_dir = APP_SUMMARY_PATH.readit()
|
|
293
338
|
if platform.system().lower() == "windows":
|
|
294
|
-
apps_dir.search("*").apply(lambda app: app.move(folder=P.get_env().WindowsApps))
|
|
339
|
+
apps_dir.search("*").apply(lambda app: app.move(folder=P.get_env().WindowsPaths().WindowsApps))
|
|
295
340
|
elif platform.system().lower() == "linux":
|
|
296
341
|
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
342
|
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()
|