machineconfig 1.5__py3-none-any.whl → 1.8__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 +8 -5
- machineconfig/jobs/python/check_installations.py +173 -163
- machineconfig/jobs/python/checkout_version.py +117 -0
- machineconfig/jobs/python/create_bootable_media.py +14 -14
- machineconfig/jobs/python/create_zellij_template.py +59 -56
- machineconfig/jobs/python/python_cargo_build_share.py +50 -45
- machineconfig/jobs/python/python_ve_symlink.py +20 -18
- machineconfig/jobs/python/tasks.py +4 -0
- machineconfig/jobs/script_installer/azure_data_studio.py +22 -0
- machineconfig/jobs/script_installer/bypass_paywall.py +23 -0
- machineconfig/jobs/script_installer/code.py +34 -0
- machineconfig/jobs/script_installer/docker_desktop.py +41 -0
- machineconfig/jobs/script_installer/ngrok.py +29 -0
- machineconfig/jobs/{python_linux_installers → script_installer}/skim.py +21 -19
- machineconfig/jobs/script_installer/wezterm.py +34 -0
- machineconfig/profile/create.py +107 -200
- machineconfig/profile/shell.py +127 -0
- machineconfig/scripts/__init__.py +6 -6
- machineconfig/scripts/python/cloud_copy.py +93 -0
- machineconfig/scripts/python/cloud_manager.py +38 -0
- machineconfig/scripts/python/cloud_mount.py +115 -52
- machineconfig/scripts/python/cloud_repo_sync.py +154 -114
- machineconfig/scripts/python/cloud_sync.py +261 -79
- machineconfig/scripts/python/croshell.py +151 -0
- machineconfig/scripts/python/devops.py +119 -87
- machineconfig/scripts/python/devops_add_identity.py +27 -23
- machineconfig/scripts/python/devops_add_ssh_key.py +70 -55
- machineconfig/scripts/python/devops_backup_retrieve.py +52 -46
- machineconfig/scripts/python/devops_devapps_install.py +120 -91
- machineconfig/scripts/python/devops_update_repos.py +82 -68
- machineconfig/scripts/python/dotfile.py +42 -38
- machineconfig/scripts/python/fire_jobs.py +351 -98
- machineconfig/scripts/python/ftpx.py +82 -0
- machineconfig/scripts/python/mount_nfs.py +54 -3
- machineconfig/scripts/python/mount_nw_drive.py +31 -0
- machineconfig/scripts/python/mount_ssh.py +44 -20
- machineconfig/scripts/python/onetimeshare.py +60 -51
- machineconfig/scripts/python/pomodoro.py +41 -37
- machineconfig/scripts/python/repos.py +195 -128
- machineconfig/scripts/python/scheduler.py +52 -0
- machineconfig/scripts/python/snapshot.py +21 -21
- machineconfig/scripts/python/start_slidev.py +104 -0
- machineconfig/scripts/python/start_terminals.py +97 -0
- machineconfig/scripts/python/wifi_conn.py +90 -71
- machineconfig/scripts/python/{transfer_wsl_win.py → wsl_windows_transfer.py} +47 -39
- machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +44 -48
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +136 -130
- machineconfig/utils/installer.py +251 -0
- machineconfig/utils/procs.py +114 -64
- machineconfig/utils/scheduling.py +188 -0
- machineconfig/utils/utils.py +353 -249
- machineconfig/utils/ve.py +222 -0
- {machineconfig-1.5.dist-info → machineconfig-1.8.dist-info}/METADATA +140 -110
- machineconfig-1.8.dist-info/RECORD +70 -0
- {machineconfig-1.5.dist-info → machineconfig-1.8.dist-info}/WHEEL +1 -1
- machineconfig/jobs/python/python_linux_installers_all.py +0 -73
- machineconfig/jobs/python/python_ve_installer.py +0 -73
- machineconfig/jobs/python/python_windows_installers_all.py +0 -23
- machineconfig/jobs/python_generic_installers/archive/nvim.py +0 -15
- machineconfig/jobs/python_generic_installers/archive/strongbox.py +0 -32
- machineconfig/jobs/python_generic_installers/archive/vtm.py +0 -25
- machineconfig/jobs/python_generic_installers/broot.py +0 -39
- machineconfig/jobs/python_generic_installers/browsh.py +0 -25
- machineconfig/jobs/python_generic_installers/bw.py +0 -26
- machineconfig/jobs/python_generic_installers/chatgpt.py +0 -24
- machineconfig/jobs/python_generic_installers/cpufetch.py +0 -23
- machineconfig/jobs/python_generic_installers/delta.py +0 -59
- machineconfig/jobs/python_generic_installers/dev/__init__.py +0 -0
- machineconfig/jobs/python_generic_installers/dev/autogpt.py +0 -28
- machineconfig/jobs/python_generic_installers/dev/bw.py +0 -29
- machineconfig/jobs/python_generic_installers/dev/evcxr.py +0 -22
- machineconfig/jobs/python_generic_installers/dev/kondo.py +0 -21
- machineconfig/jobs/python_generic_installers/dev/lvim.py +0 -60
- machineconfig/jobs/python_generic_installers/dev/ngrok.py +0 -35
- machineconfig/jobs/python_generic_installers/dev/opencommit.py +0 -21
- machineconfig/jobs/python_generic_installers/dev/qrcp.py +0 -25
- machineconfig/jobs/python_generic_installers/dev/qrscan.py +0 -16
- machineconfig/jobs/python_generic_installers/dev/rust-analyzer.py +0 -24
- machineconfig/jobs/python_generic_installers/dev/termscp.py +0 -23
- machineconfig/jobs/python_generic_installers/dev/tldr.py +0 -25
- machineconfig/jobs/python_generic_installers/dev/tokei.py +0 -24
- machineconfig/jobs/python_generic_installers/diskonaut.py +0 -26
- machineconfig/jobs/python_generic_installers/dua.py +0 -21
- machineconfig/jobs/python_generic_installers/evcxr.py +0 -21
- machineconfig/jobs/python_generic_installers/gitui.py +0 -23
- machineconfig/jobs/python_generic_installers/gopass.py +0 -19
- machineconfig/jobs/python_generic_installers/helix.py +0 -45
- machineconfig/jobs/python_generic_installers/kondo.py +0 -20
- machineconfig/jobs/python_generic_installers/lf.py +0 -25
- machineconfig/jobs/python_generic_installers/lvim.py +0 -34
- machineconfig/jobs/python_generic_installers/mprocs.py +0 -20
- machineconfig/jobs/python_generic_installers/navi.py +0 -20
- machineconfig/jobs/python_generic_installers/ots.py +0 -26
- machineconfig/jobs/python_generic_installers/ouch.py +0 -25
- machineconfig/jobs/python_generic_installers/pomodoro.py +0 -19
- machineconfig/jobs/python_generic_installers/procs.py +0 -20
- machineconfig/jobs/python_generic_installers/qrcp.py +0 -22
- machineconfig/jobs/python_generic_installers/qrscan.py +0 -14
- machineconfig/jobs/python_generic_installers/rclone.py +0 -21
- machineconfig/jobs/python_generic_installers/rust-analyzer.py +0 -24
- machineconfig/jobs/python_generic_installers/tere.py +0 -26
- machineconfig/jobs/python_generic_installers/termscp.py +0 -23
- machineconfig/jobs/python_generic_installers/tldr.py +0 -24
- machineconfig/jobs/python_generic_installers/tokei.py +0 -21
- machineconfig/jobs/python_generic_installers/vtm.py +0 -26
- machineconfig/jobs/python_generic_installers/watchexec.py +0 -21
- machineconfig/jobs/python_linux_installers/archive/__init__.py +0 -0
- machineconfig/jobs/python_linux_installers/archive/ranger.py +0 -18
- machineconfig/jobs/python_linux_installers/bandwhich.py +0 -11
- machineconfig/jobs/python_linux_installers/bottom.py +0 -17
- machineconfig/jobs/python_linux_installers/btop.py +0 -17
- machineconfig/jobs/python_linux_installers/dev/bandwhich.py +0 -13
- machineconfig/jobs/python_linux_installers/dev/bytehound.py +0 -20
- machineconfig/jobs/python_linux_installers/dev/nnn.py +0 -21
- machineconfig/jobs/python_linux_installers/gotty.py +0 -16
- machineconfig/jobs/python_linux_installers/joshuto.py +0 -28
- machineconfig/jobs/python_linux_installers/mcfly.py +0 -12
- machineconfig/jobs/python_linux_installers/nnn.py +0 -18
- machineconfig/jobs/python_linux_installers/topgrade.py +0 -15
- machineconfig/jobs/python_linux_installers/viu.py +0 -19
- machineconfig/jobs/python_linux_installers/xplr.py +0 -22
- machineconfig/jobs/python_linux_installers/zellij.py +0 -31
- machineconfig/jobs/python_windows_installers/archive/ntop.py +0 -20
- machineconfig/jobs/python_windows_installers/bat.py +0 -16
- machineconfig/jobs/python_windows_installers/boxes.py +0 -19
- machineconfig/jobs/python_windows_installers/bypass_paywall.py +0 -18
- machineconfig/jobs/python_windows_installers/dev/bypass_paywall.py +0 -21
- machineconfig/jobs/python_windows_installers/dev/obs_background_removal_plugin.py +0 -20
- machineconfig/jobs/python_windows_installers/fd.py +0 -17
- machineconfig/jobs/python_windows_installers/fzf.py +0 -19
- machineconfig/jobs/python_windows_installers/obs_background_removal_plugin.py +0 -19
- machineconfig/jobs/python_windows_installers/rg.py +0 -15
- machineconfig/jobs/python_windows_installers/ugrep.py +0 -14
- machineconfig/jobs/python_windows_installers/zoomit.py +0 -20
- machineconfig/jobs/python_windows_installers/zoxide.py +0 -20
- machineconfig/profile/fix_shell_profiles.py +0 -8
- machineconfig/scripts/python/archive/__init__.py +0 -0
- machineconfig/scripts/python/archive/bu_gdrive_rx.py +0 -41
- machineconfig/scripts/python/archive/bu_gdrive_sx.py +0 -40
- machineconfig/scripts/python/archive/bu_onedrive_rx.py +0 -59
- machineconfig/scripts/python/archive/bu_onedrive_sx.py +0 -45
- machineconfig/scripts/python/chatgpt.py +0 -28
- machineconfig/scripts/python/choose_ohmybash_theme.py +0 -25
- machineconfig/scripts/python/choose_ohmyposh_theme.py +0 -40
- machineconfig/scripts/python/cloud_rx.py +0 -42
- machineconfig/scripts/python/cloud_sx.py +0 -40
- machineconfig/scripts/python/ftprx.py +0 -37
- machineconfig/scripts/python/ftpsx.py +0 -36
- machineconfig/scripts/python/im2text.py +0 -15
- machineconfig/scripts/python/tmate_conn.py +0 -28
- machineconfig/scripts/python/tmate_start.py +0 -31
- machineconfig/utils/to_exe.py +0 -7
- machineconfig-1.5.dist-info/RECORD +0 -147
- /machineconfig/jobs/{python_generic_installers/archive → script_installer}/__init__.py +0 -0
- {machineconfig-1.5.dist-info → machineconfig-1.8.dist-info}/top_level.txt +0 -0
|
@@ -1,130 +1,136 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
self.dat[
|
|
36
|
-
self.dat["
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
self.dat["
|
|
40
|
-
self.dat
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
ts
|
|
123
|
-
ts.
|
|
124
|
-
ts.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
1
|
+
|
|
2
|
+
"""Set Windows Terminal Settings
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from crocodile.core import randstr, List as L
|
|
6
|
+
from crocodile.file_management import P, Read, Save
|
|
7
|
+
import crocodile.environment as env
|
|
8
|
+
from machineconfig.utils.utils import LIBRARY_ROOT
|
|
9
|
+
from uuid import uuid4
|
|
10
|
+
import os
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
Not to be confused:
|
|
16
|
+
* Windows Terminal & Windows Terminal Preview: The latter is the night release version of WT.
|
|
17
|
+
* Windows PowerShell & PowerShell: The latter is community developed and is available on all platforms.
|
|
18
|
+
* Windows Powershell comes preinstalled with the system, Powershell must be installed separately.
|
|
19
|
+
* Lastly, powershell has a preview version as well.
|
|
20
|
+
All settings are available on GitHub: https://aka.ms/terminal-profiles-schema
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
assert env.system == 'Windows', 'This script is only for Windows.'
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class TerminalSettings(object):
|
|
28
|
+
def __init__(self):
|
|
29
|
+
# Grabbing Terminal Settings file:
|
|
30
|
+
tmp = os.getenv("LOCALAPPDATA")
|
|
31
|
+
if not isinstance(tmp, str):
|
|
32
|
+
raise ValueError("Could not find LOCALAPPDATA environment variable.")
|
|
33
|
+
self.path = P(tmp).joinpath(r"Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json")
|
|
34
|
+
self.path.copy(append=".orig_" + randstr())
|
|
35
|
+
self.dat: dict[str, Any] = Read.json(self.path)
|
|
36
|
+
self.profs = L(self.dat["profiles"]["list"])
|
|
37
|
+
|
|
38
|
+
def save_terminal_settings(self):
|
|
39
|
+
self.dat["profiles"]["list"] = list(self.profs)
|
|
40
|
+
Save.json(obj=self.dat, path=self.path, indent=5)
|
|
41
|
+
|
|
42
|
+
# ========================= Terminal Settings =========================================
|
|
43
|
+
def update_default_settings(self):
|
|
44
|
+
# Changing start up settings:
|
|
45
|
+
self.dat["startOnUserLogin"] = True
|
|
46
|
+
self.dat["launchMode"] = "fullscreen"
|
|
47
|
+
self.dat["theme"] = "dark"
|
|
48
|
+
self.dat["focusFollowMouse"] = True
|
|
49
|
+
self.dat["copyOnSelect"] = True
|
|
50
|
+
self.dat["profiles"]["defaults"]["padding"] = "0"
|
|
51
|
+
self.dat["profiles"]["defaults"]["useAcrylic"] = False
|
|
52
|
+
|
|
53
|
+
# 1- Customizing Powershell========================================================
|
|
54
|
+
# as opposed to Windows Powershell
|
|
55
|
+
def customize_powershell(self, nerd_font: bool = True):
|
|
56
|
+
pwsh: dict[str, Any] = dict(name="PowerShell",
|
|
57
|
+
commandline="pwsh",
|
|
58
|
+
hidden=False,
|
|
59
|
+
opacity=87,
|
|
60
|
+
# guid="{" + str(uuid4()) + "}", # WT doesn't accept any GUID to identify pwsh
|
|
61
|
+
startingDirectory="%USERPROFILE%", # "%USERPROFILE%", # None: inherent from parent process.
|
|
62
|
+
)
|
|
63
|
+
if nerd_font: pwsh["font"] = dict(face="CaskaydiaCove Nerd Font") # because oh-my-posh uses glyphs from this font.
|
|
64
|
+
for idx, item in enumerate(self.profs):
|
|
65
|
+
if item["name"] == "PowerShell":
|
|
66
|
+
self.profs.list[idx].update(pwsh)
|
|
67
|
+
break
|
|
68
|
+
else: print(f"Couldn't customize powershell because profile not found, try to install it first.")
|
|
69
|
+
|
|
70
|
+
def make_powershell_default_profile(self):
|
|
71
|
+
for profile in self.profs:
|
|
72
|
+
if profile["name"] == "PowerShell":
|
|
73
|
+
self.dat["defaultProfile"] = profile["guid"]
|
|
74
|
+
print("Powershell is now the default profile.")
|
|
75
|
+
break
|
|
76
|
+
else: print("Powershell profile was not found in the list of profile and therefore was not made the deafult.")
|
|
77
|
+
|
|
78
|
+
def add_croshell(self):
|
|
79
|
+
croshell = dict(name="croshell",
|
|
80
|
+
guid="{" + str(uuid4()) + "}",
|
|
81
|
+
# commandline=f"powershell.exe -Command \"{activate} ipython -i -c 'from crocodile.toolbox import *'\"",
|
|
82
|
+
commandline=f'powershell.exe -Command "{LIBRARY_ROOT.as_posix()}/scripts/windows/croshell.ps1"',
|
|
83
|
+
startingDirectory="%USERPROFILE%", # "%USERPROFILE%", # None: inherent from parent process.
|
|
84
|
+
)
|
|
85
|
+
# startingDirectory = None means: inheret from parent process, which will is the default, which point to /System32
|
|
86
|
+
# Launching a new profile with ctr+shift+2 is equivalent to: wt --profile croshell -d . --new-tab
|
|
87
|
+
for profile in self.profs:
|
|
88
|
+
if profile["name"] == "croshell":
|
|
89
|
+
profile.update(croshell)
|
|
90
|
+
break
|
|
91
|
+
else: self.profs.append(croshell)
|
|
92
|
+
|
|
93
|
+
def add_ubuntu(self):
|
|
94
|
+
# Add Ubunto if it is not there.
|
|
95
|
+
ubuntu = dict(name="Ubuntu",
|
|
96
|
+
commandline="wsl -d Ubuntu -- cd ~",
|
|
97
|
+
hidden=False,
|
|
98
|
+
guid="{" + str(uuid4()) + "}",
|
|
99
|
+
startingDirectory="%USERPROFILE%", # "%USERPROFILE%", # None: inherent from parent process.
|
|
100
|
+
)
|
|
101
|
+
if self.profs.filter(lambda x: x["name"] == "Ubuntu").__len__() < 1: self.profs.append(ubuntu)
|
|
102
|
+
|
|
103
|
+
def standardize_profiles_order(self):
|
|
104
|
+
# Changing order of profiles:
|
|
105
|
+
others = []
|
|
106
|
+
pwsh = croshell = ubuntu = wpwsh = cmd = azure = None
|
|
107
|
+
for profile in self.profs:
|
|
108
|
+
name = profile["name"]
|
|
109
|
+
if name == "PowerShell": pwsh = profile
|
|
110
|
+
elif name == "croshell": croshell = profile
|
|
111
|
+
elif name == "Ubuntu": ubuntu = profile
|
|
112
|
+
elif name == "Windows PowerShell": wpwsh = profile
|
|
113
|
+
elif name == "Command Prompt": cmd = profile
|
|
114
|
+
elif name == "Azure Cloud Shell": azure = profile
|
|
115
|
+
else: others.append(profile)
|
|
116
|
+
self.profs = L([item for item in [pwsh, croshell, ubuntu, wpwsh, cmd, azure] + others if item is not None])
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def main():
|
|
120
|
+
shell = {"powershell": "pwsh.exe", "Windows Powershell": "powershell.exe"}["powershell"].split(".exe", maxsplit=1)[0]
|
|
121
|
+
if shell == "pwsh":
|
|
122
|
+
ts = TerminalSettings()
|
|
123
|
+
ts.update_default_settings()
|
|
124
|
+
ts.customize_powershell(nerd_font=True)
|
|
125
|
+
|
|
126
|
+
ts.make_powershell_default_profile()
|
|
127
|
+
ts.add_croshell()
|
|
128
|
+
ts.add_ubuntu()
|
|
129
|
+
ts.standardize_profiles_order()
|
|
130
|
+
ts.dat['actions'].append({'command': 'togglePaneZoom', 'keys': 'ctrl+shift+z'})
|
|
131
|
+
ts.save_terminal_settings()
|
|
132
|
+
else: raise NotImplementedError
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
if __name__ == '__main__':
|
|
136
|
+
pass
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
|
|
2
|
+
"""package manager
|
|
3
|
+
"""
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
|
|
6
|
+
from crocodile.file_management import P, List as L, Read, Struct
|
|
7
|
+
from crocodile.meta import Terminal
|
|
8
|
+
from machineconfig.utils.utils import INSTALL_VERSION_ROOT, INSTALL_TMP_DIR, LIBRARY_ROOT, check_tool_exists
|
|
9
|
+
|
|
10
|
+
# from dataclasses import dataclass
|
|
11
|
+
from typing import Optional, Any
|
|
12
|
+
import platform
|
|
13
|
+
# import os
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def find_move_delete_windows(downloaded_file_path: P, exe_name: Optional[str] = None, delete: bool = True, rename_to: Optional[str] = None):
|
|
17
|
+
if exe_name is not None and ".exe" in exe_name: exe_name = exe_name.replace(".exe", "")
|
|
18
|
+
if downloaded_file_path.is_file():
|
|
19
|
+
exe = downloaded_file_path
|
|
20
|
+
else:
|
|
21
|
+
if exe_name is None: exe = downloaded_file_path.search("*.exe", r=True).list[0]
|
|
22
|
+
else:
|
|
23
|
+
tmp = downloaded_file_path.search(f"{exe_name}.exe", r=True)
|
|
24
|
+
if len(tmp) == 1: exe = tmp.list[0]
|
|
25
|
+
else: exe = downloaded_file_path.search("*.exe", r=True).list[0]
|
|
26
|
+
if rename_to and exe.name != rename_to:
|
|
27
|
+
exe = exe.with_name(name=rename_to, inplace=True)
|
|
28
|
+
exe_new_location = exe.move(folder=P.get_env().WindowsApps, overwrite=True) # latest version overwrites older installation.
|
|
29
|
+
if delete: downloaded_file_path.delete(sure=True)
|
|
30
|
+
return exe_new_location
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def find_move_delete_linux(downloaded: P, tool_name: str, delete: Optional[bool] = True, rename_to: Optional[str] = None):
|
|
34
|
+
if downloaded.is_file():
|
|
35
|
+
exe = downloaded
|
|
36
|
+
else:
|
|
37
|
+
res = downloaded.search(f"*{tool_name}*", folders=False, r=True)
|
|
38
|
+
if len(res) == 1: exe = res.list[0]
|
|
39
|
+
else:
|
|
40
|
+
exe_search_res = downloaded.search(tool_name, folders=False, r=True)
|
|
41
|
+
if len(exe_search_res) == 0:
|
|
42
|
+
print(f"No search results for `{tool_name}` in `{downloaded}`")
|
|
43
|
+
raise IndexError(f"No executable found in {downloaded}")
|
|
44
|
+
else:
|
|
45
|
+
exe = exe_search_res.list[0]
|
|
46
|
+
if rename_to and exe.name != rename_to:
|
|
47
|
+
exe = exe.with_name(name=rename_to, inplace=True)
|
|
48
|
+
print(f"MOVING file `{repr(exe)}` to '/usr/local/bin'")
|
|
49
|
+
exe.chmod(0o777)
|
|
50
|
+
# exe.move(folder=r"/usr/local/bin", overwrite=False)
|
|
51
|
+
Terminal().run(f"sudo mv {exe} /usr/local/bin/").print_if_unsuccessful(desc="MOVING executable to /usr/local/bin", strict_err=True, strict_returncode=True)
|
|
52
|
+
if delete: downloaded.delete(sure=True)
|
|
53
|
+
exe_new_location = P(r"/usr/local/bin").joinpath(exe.name)
|
|
54
|
+
return exe_new_location
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class Installer:
|
|
58
|
+
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):
|
|
59
|
+
self.repo_url = repo_url
|
|
60
|
+
self.name = name
|
|
61
|
+
self.doc = doc
|
|
62
|
+
self.filename_template_windows_amd_64 = filename_template_windows_amd_64
|
|
63
|
+
self.filename_template_linux_amd_64 = filename_template_linux_amd_64
|
|
64
|
+
self.strip_v = strip_v
|
|
65
|
+
self.exe_name = exe_name
|
|
66
|
+
def __repr__(self) -> str: return f"Installer of {self.repo_url}"
|
|
67
|
+
def get_description(self):
|
|
68
|
+
# old_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
|
|
69
|
+
# old_version_cli = os.system(f"{self.exe_name} --version").replace("\n", "")
|
|
70
|
+
old_version_cli = check_tool_exists(self.exe_name)
|
|
71
|
+
old_version_cli_str = "✅" if old_version_cli else "❌"
|
|
72
|
+
# name_version = f"{self.exe_name} {old_version_cli_str}"
|
|
73
|
+
return f"{self.exe_name:<12} {old_version_cli_str} {self.doc}"
|
|
74
|
+
def to_dict(self): return self.__dict__
|
|
75
|
+
@staticmethod
|
|
76
|
+
def from_dict(d: dict[str, Any], name: str):
|
|
77
|
+
try: return Installer(name=name, **d)
|
|
78
|
+
except Exception as ex:
|
|
79
|
+
Struct(d).print(as_config=True)
|
|
80
|
+
raise ex
|
|
81
|
+
@staticmethod
|
|
82
|
+
def choose_app_and_install():
|
|
83
|
+
from machineconfig.utils.utils import choose_one_option
|
|
84
|
+
path = choose_one_option(options=LIBRARY_ROOT.joinpath("jobs").search("config.json", r=True).list)
|
|
85
|
+
config: dict[str, Any] = Read.json(path) # /python_generic_installers/config.json"))
|
|
86
|
+
# binary = choose_one_option(options=list(config.keys()), fzf=True)
|
|
87
|
+
for keys, dict_ in config.items():
|
|
88
|
+
installer = Installer.from_dict(d=dict_, name=keys)
|
|
89
|
+
installer.install(version=None)
|
|
90
|
+
|
|
91
|
+
def install_robust(self, version: Optional[str]):
|
|
92
|
+
try:
|
|
93
|
+
old_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
|
|
94
|
+
self.install(version=version)
|
|
95
|
+
new_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
|
|
96
|
+
if old_version_cli == new_version_cli: return f"📦️ 😑 {self.exe_name}, same version: {old_version_cli}"
|
|
97
|
+
else: return f"📦️ 🤩 {self.exe_name} updated from {old_version_cli} === to ===> {new_version_cli}"
|
|
98
|
+
except Exception as ex:
|
|
99
|
+
print(ex)
|
|
100
|
+
return f"📦️ Failed at {self.exe_name} with {ex}"
|
|
101
|
+
|
|
102
|
+
def install(self, version: Optional[str]):
|
|
103
|
+
if self.repo_url == "CUSTOM":
|
|
104
|
+
import machineconfig.jobs.script_installer as custom_installer
|
|
105
|
+
installer_path = P(custom_installer.__file__).parent.joinpath(self.exe_name + ".py")
|
|
106
|
+
import runpy
|
|
107
|
+
program = runpy.run_path(str(installer_path), run_name="__main__")['main'](version=version)
|
|
108
|
+
Terminal().run(program, shell="default")
|
|
109
|
+
version_to_be_installed = str(version)
|
|
110
|
+
elif "npm " in self.repo_url:
|
|
111
|
+
Terminal().run(self.repo_url, shell="default").print_if_unsuccessful(desc="npm install", strict_err=True, strict_returncode=True)
|
|
112
|
+
version_to_be_installed = "npmLatest"
|
|
113
|
+
elif "pip " in self.repo_url:
|
|
114
|
+
Terminal().run(self.repo_url, shell="default").print_if_unsuccessful(desc="pip install", strict_err=True, strict_returncode=True)
|
|
115
|
+
version_to_be_installed = "pipLatest"
|
|
116
|
+
else:
|
|
117
|
+
downloaded, version_to_be_installed = self.download(version=version)
|
|
118
|
+
if downloaded.str.endswith(".deb"):
|
|
119
|
+
assert platform.system() == "Linux"
|
|
120
|
+
Terminal().run(f"sudo apt install -y {downloaded}").print_if_unsuccessful(desc="Installing .deb", strict_err=True, strict_returncode=True)
|
|
121
|
+
downloaded.delete(sure=True)
|
|
122
|
+
else:
|
|
123
|
+
if platform.system() == "Windows":
|
|
124
|
+
exe = find_move_delete_windows(downloaded_file_path=downloaded, exe_name=self.exe_name, delete=True, rename_to=self.exe_name + ".exe")
|
|
125
|
+
elif platform.system() == "Linux":
|
|
126
|
+
exe = find_move_delete_linux(downloaded=downloaded, tool_name=self.exe_name, delete=True, rename_to=self.exe_name)
|
|
127
|
+
else: raise NotImplementedError(f"System {platform.system()} not implemented")
|
|
128
|
+
_ = exe
|
|
129
|
+
if exe.name.replace(".exe", "") != self.exe_name.replace(".exe", ""):
|
|
130
|
+
from rich import print as pprint
|
|
131
|
+
from rich.panel import Panel
|
|
132
|
+
pprint(Panel(f"Expected exe name: [red]{self.exe_name}[/red] \nAttained name: [red]{exe.name.replace('.exe', '')}[/red]", title="exe name mismatch", subtitle=self.repo_url))
|
|
133
|
+
new_exe_name = self.exe_name + ".exe" if platform.system() == "Windows" else self.exe_name
|
|
134
|
+
exe.with_name(name=new_exe_name, inplace=True, overwrite=True)
|
|
135
|
+
INSTALL_VERSION_ROOT.joinpath(self.exe_name).create(parents_only=True).write_text(version_to_be_installed)
|
|
136
|
+
|
|
137
|
+
def download(self, version: Optional[str]):
|
|
138
|
+
if "github" not in self.repo_url or ".zip" in self.repo_url or ".tar.gz" in self.repo_url:
|
|
139
|
+
download_link = P(self.repo_url)
|
|
140
|
+
version_to_be_installed = "predefined_url"
|
|
141
|
+
print(f"📦️ Version to be installed: {version_to_be_installed}")
|
|
142
|
+
elif "http" in self.filename_template_linux_amd_64 or "http" in self.filename_template_windows_amd_64:
|
|
143
|
+
if platform.system() == "Windows":
|
|
144
|
+
download_link = P(self.filename_template_windows_amd_64)
|
|
145
|
+
elif platform.system() == "Linux":
|
|
146
|
+
download_link = P(self.filename_template_linux_amd_64)
|
|
147
|
+
else: raise NotImplementedError(f"📦️ System {platform.system()} not implemented")
|
|
148
|
+
version_to_be_installed = "predefined_url"
|
|
149
|
+
else:
|
|
150
|
+
release_url, version_to_be_installed = self.get_github_release(repo_url=self.repo_url, version=version)
|
|
151
|
+
print(f"📦️ Version to be installed: {version_to_be_installed}")
|
|
152
|
+
print(f"📦️ Release URL: {release_url}")
|
|
153
|
+
version_to_be_installed_stripped = version_to_be_installed.replace("v", "") if self.strip_v else version_to_be_installed
|
|
154
|
+
if platform.system() == "Windows":
|
|
155
|
+
file_name = self.filename_template_windows_amd_64.format(version_to_be_installed_stripped)
|
|
156
|
+
elif platform.system() == "Linux":
|
|
157
|
+
file_name = self.filename_template_linux_amd_64.format(version_to_be_installed_stripped)
|
|
158
|
+
else: raise NotImplementedError(f"📦️ System {platform.system()} not implemented")
|
|
159
|
+
print(f"📦️ File name", file_name)
|
|
160
|
+
download_link = release_url.joinpath(file_name)
|
|
161
|
+
print("📦️ Downloading: ", download_link.as_url_str())
|
|
162
|
+
downloaded = download_link.download(folder=INSTALL_TMP_DIR).decompress()
|
|
163
|
+
return downloaded, version_to_be_installed
|
|
164
|
+
|
|
165
|
+
@staticmethod
|
|
166
|
+
def get_github_release(repo_url: str, version: Optional[str] = None):
|
|
167
|
+
print("\n\n\n")
|
|
168
|
+
print(f"📦️ Inspecting latest release @ {repo_url} ...")
|
|
169
|
+
# with console.status("Installing..."): # makes troubles on linux when prompt asks for password to move file to /usr/bin
|
|
170
|
+
if version is None:
|
|
171
|
+
import requests # https://docs.github.com/en/repositories/releasing-projects-on-github/linking-to-releases
|
|
172
|
+
_latest_version = requests.get(str(repo_url) + "/releases/latest", timeout=10).url.split("/")[-1] # this is to resolve the redirection that occures: https://stackoverflow.com/questions/36070821/how-to-get-redirect-url-using-python-requests
|
|
173
|
+
version_to_be_installed = _latest_version
|
|
174
|
+
# print(version_to_be_installed)
|
|
175
|
+
else:
|
|
176
|
+
version_to_be_installed = version
|
|
177
|
+
release_url = P(repo_url + "/releases/download/" + version_to_be_installed)
|
|
178
|
+
return release_url, version_to_be_installed
|
|
179
|
+
|
|
180
|
+
@staticmethod
|
|
181
|
+
def check_if_installed_already(exe_name: str, version: str):
|
|
182
|
+
version_to_be_installed = version
|
|
183
|
+
tmp_path = INSTALL_VERSION_ROOT.joinpath(exe_name).create(parents_only=True)
|
|
184
|
+
if tmp_path.exists(): existing_version = tmp_path.read_text().rstrip()
|
|
185
|
+
else: existing_version = None
|
|
186
|
+
|
|
187
|
+
if existing_version is not None:
|
|
188
|
+
if existing_version == version_to_be_installed:
|
|
189
|
+
print(f"📦️ ⚠️ {exe_name} already installed at version {version_to_be_installed}. See {INSTALL_VERSION_ROOT}")
|
|
190
|
+
return True
|
|
191
|
+
else:
|
|
192
|
+
# print(f"Latest version is {version}, logged at {tmp_path}")
|
|
193
|
+
print(f"📦️ ⬆️ {exe_name} installed at version {existing_version.rstrip()} --> Installing version {version_to_be_installed} ")
|
|
194
|
+
tmp_path.write_text(version_to_be_installed)
|
|
195
|
+
else:
|
|
196
|
+
print(f"📦️ {exe_name} has no known version. Installing version `{version_to_be_installed}` ")
|
|
197
|
+
tmp_path.write_text(version_to_be_installed)
|
|
198
|
+
return False
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def get_installed_cli_apps():
|
|
202
|
+
if platform.system() == "Windows": apps = P.home().joinpath("AppData/Local/Microsoft/WindowsApps").search("*.exe", not_in=["notepad"])
|
|
203
|
+
elif platform.system() == "Linux": apps = P(r"/usr/local/bin").search("*")
|
|
204
|
+
else: raise NotImplementedError("Not implemented for this OS")
|
|
205
|
+
apps = L([app for app in apps if app.size("kb") > 0.1 and not app.is_symlink()]) # no symlinks like paint and wsl and bash
|
|
206
|
+
return apps
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def get_installers(system: str, dev: bool) -> list[Installer]:
|
|
210
|
+
if system == "Windows": import machineconfig.jobs.python_windows_installers as os_specific_installer
|
|
211
|
+
else: import machineconfig.jobs.python_linux_installers as os_specific_installer
|
|
212
|
+
import machineconfig.jobs.python_generic_installers as generic_installer
|
|
213
|
+
path = P(os_specific_installer.__file__).parent
|
|
214
|
+
gens_path = P(generic_installer.__file__).parent
|
|
215
|
+
if dev:
|
|
216
|
+
path = path.joinpath("dev")
|
|
217
|
+
gens_path = gens_path.joinpath("dev")
|
|
218
|
+
res1: dict[str, Any] = Read.json(path=path.joinpath("config.json"))
|
|
219
|
+
res2: dict[str, Any] = Read.json(path=gens_path.joinpath("config.json"))
|
|
220
|
+
res2.update(res1)
|
|
221
|
+
return [Installer.from_dict(d=vd, name=k) for k, vd in res2.items()]
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def install_all(installers: L[Installer], safe: bool = False, jobs: int = 10, fresh: bool = False):
|
|
225
|
+
if fresh: INSTALL_VERSION_ROOT.delete(sure=True)
|
|
226
|
+
if safe:
|
|
227
|
+
from machineconfig.jobs.python.check_installations import APP_SUMMARY_PATH
|
|
228
|
+
apps_dir = APP_SUMMARY_PATH.readit()
|
|
229
|
+
if platform.system().lower() == "windows":
|
|
230
|
+
apps_dir.search("*").apply(lambda app: app.move(folder=P.get_env().WindowsApps))
|
|
231
|
+
elif platform.system().lower() == "linux":
|
|
232
|
+
Terminal().run(f"sudo mv {apps_dir.as_posix()}/* /usr/local/bin/").print_if_unsuccessful(desc="MOVING executable to /usr/local/bin", strict_err=True, strict_returncode=True)
|
|
233
|
+
else: raise NotImplementedError(f"I don't know this system {platform.system()}")
|
|
234
|
+
apps_dir.delete(sure=True)
|
|
235
|
+
return None
|
|
236
|
+
installers.list[0].install(version=None)
|
|
237
|
+
res = installers.slice(start=1).apply(lambda x: x.install_robust(version=None), jobs=jobs) # try out the first installer alone cause it will ask for password, so the rest will inherit the sudo session.
|
|
238
|
+
console = Console()
|
|
239
|
+
print("\n")
|
|
240
|
+
console.rule("Same version apps")
|
|
241
|
+
print(f"{res.filter(lambda x: 'same version' in x).print()}")
|
|
242
|
+
print("\n")
|
|
243
|
+
console.rule("Updated apps")
|
|
244
|
+
print(f"{res.filter(lambda x: 'updated from' in x).print()}")
|
|
245
|
+
print("\n")
|
|
246
|
+
console.rule("Failed apps")
|
|
247
|
+
print(f"{res.filter(lambda x: 'Failed at' in x).print()}")
|
|
248
|
+
|
|
249
|
+
print("\n")
|
|
250
|
+
print("Completed Installation".center(100, "-"))
|
|
251
|
+
print("\n" * 2)
|