machineconfig 6.59__py3-none-any.whl → 6.62__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/jobs/installer/installer_data.json +17 -0
- machineconfig/profile/create_shell_profile.py +2 -2
- machineconfig/scripts/python/croshell.py +6 -3
- machineconfig/scripts/python/env_manager/path_manager_tui.py +1 -1
- machineconfig/scripts/python/ftpx.py +1 -1
- machineconfig/scripts/python/helpers_devops/cli_config.py +1 -1
- machineconfig/scripts/python/helpers_devops/cli_self.py +3 -3
- machineconfig/scripts/python/helpers_devops/cli_utils.py +26 -1
- machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +1 -1
- machineconfig/scripts/python/nw/mount_nfs +1 -1
- machineconfig/scripts/python/utils.py +3 -1
- machineconfig/scripts/windows/mounts/mount_ssh.ps1 +1 -1
- machineconfig/settings/shells/pwsh/init.ps1 +2 -2
- machineconfig/setup_linux/web_shortcuts/interactive.sh +3 -3
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +3 -3
- machineconfig/utils/ssh.py +71 -127
- machineconfig/utils/terminal.py +2 -113
- {machineconfig-6.59.dist-info → machineconfig-6.62.dist-info}/METADATA +1 -1
- {machineconfig-6.59.dist-info → machineconfig-6.62.dist-info}/RECORD +22 -22
- {machineconfig-6.59.dist-info → machineconfig-6.62.dist-info}/WHEEL +0 -0
- {machineconfig-6.59.dist-info → machineconfig-6.62.dist-info}/entry_points.txt +0 -0
- {machineconfig-6.59.dist-info → machineconfig-6.62.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "1",
|
|
3
3
|
"installers": [
|
|
4
|
+
{
|
|
5
|
+
"appName": "fx",
|
|
6
|
+
"repoURL": "https://github.com/antonmedv/fx",
|
|
7
|
+
"doc": "🧙♂️ Command-line JSON viewer",
|
|
8
|
+
"fileNamePattern": {
|
|
9
|
+
"amd64": {
|
|
10
|
+
"linux": "fx_linux_amd64",
|
|
11
|
+
"windows": "fx_windows_amd64.exe",
|
|
12
|
+
"macos": "fx_darwin_amd64"
|
|
13
|
+
},
|
|
14
|
+
"arm64": {
|
|
15
|
+
"linux": "fx_linux_arm64",
|
|
16
|
+
"windows": "fx_windows_arm64.exe",
|
|
17
|
+
"macos": "fx_darwin_arm64"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
4
21
|
{
|
|
5
22
|
"appName": "jq",
|
|
6
23
|
"repoURL": "https://github.com/jqlang/jq",
|
|
@@ -17,11 +17,11 @@ console = Console()
|
|
|
17
17
|
BOX_WIDTH = 100 # Define BOX_WIDTH or get it from a config
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
def get_shell_profile_path() ->
|
|
20
|
+
def get_shell_profile_path() -> Path:
|
|
21
21
|
if system == "Windows":
|
|
22
22
|
result = subprocess.run(["pwsh", "-Command", "$PROFILE"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False)
|
|
23
23
|
if result.returncode == 0 and result.stdout.strip():
|
|
24
|
-
profile_path =
|
|
24
|
+
profile_path = Path(result.stdout.strip())
|
|
25
25
|
else:
|
|
26
26
|
print(f"Command failed with return code {result.returncode}")
|
|
27
27
|
print(f"stdout: {result.stdout}")
|
|
@@ -65,8 +65,8 @@ def croshell(
|
|
|
65
65
|
text = f"📄 Reading data from: {file_obj.name}"
|
|
66
66
|
console.print(Panel(text, title="[bold blue]Info[/bold blue]"))
|
|
67
67
|
else: # if nothing is specified, then run in interactive mode.
|
|
68
|
-
text = "⌨️ Entering interactive mode"
|
|
69
|
-
console.print(Panel(text, title="[bold blue]Info[/bold blue]"))
|
|
68
|
+
# text = "⌨️ Entering interactive mode"
|
|
69
|
+
# console.print(Panel(text, title="[bold blue]Info[/bold blue]"))
|
|
70
70
|
# from machineconfig.scripts.python.croshell import InteractiveShell
|
|
71
71
|
# InteractiveShell().run()
|
|
72
72
|
# return None
|
|
@@ -124,7 +124,10 @@ def croshell(
|
|
|
124
124
|
# if writing fails, fall back to the default nb_target already set
|
|
125
125
|
pass
|
|
126
126
|
if visidata:
|
|
127
|
-
|
|
127
|
+
if file_obj.suffix == ".json":
|
|
128
|
+
fire_line = f"uv run --with visidata vd {str(file_obj)}"
|
|
129
|
+
else:
|
|
130
|
+
fire_line = f"uv run --with visidata,pyarrow vd {str(file_obj)}"
|
|
128
131
|
elif marimo:
|
|
129
132
|
if Path.home().joinpath("code/machineconfig").exists(): requirements = f"""--with marimo --project "{str(Path.home().joinpath("code/machineconfig"))}" """
|
|
130
133
|
else: requirements = """--with "marimo,machineconfig[plot]>=6.57" """
|
|
@@ -183,7 +183,7 @@ def ftpx(
|
|
|
183
183
|
padding=(1, 2),
|
|
184
184
|
)
|
|
185
185
|
)
|
|
186
|
-
received_file = ssh.copy_from_here(source_path=resolved_source,
|
|
186
|
+
received_file = ssh.copy_from_here(source_path=resolved_source, target_rel2home=resolved_target, compress_with_zip=zipFirst, recursive=recursive, overwrite_existing=False)
|
|
187
187
|
|
|
188
188
|
if source_is_remote and isinstance(received_file, PathExtended):
|
|
189
189
|
console.print(
|
|
@@ -46,7 +46,7 @@ def path():
|
|
|
46
46
|
uv_with = ["textual"]
|
|
47
47
|
uv_project_dir = None
|
|
48
48
|
if not Path.home().joinpath("code/machineconfig").exists():
|
|
49
|
-
uv_with.append("machineconfig>=6.
|
|
49
|
+
uv_with.append("machineconfig>=6.61")
|
|
50
50
|
else:
|
|
51
51
|
uv_project_dir = str(Path.home().joinpath("code/machineconfig"))
|
|
52
52
|
run_shell_script(get_uv_command_executing_python_script(python_script=path.read_text(encoding="utf-8"), uv_with=uv_with, uv_project_dir=uv_project_dir)[0])
|
|
@@ -41,9 +41,9 @@ def install(no_copy_assets: Annotated[bool, typer.Option("--no-assets-copy", "-n
|
|
|
41
41
|
else:
|
|
42
42
|
import platform
|
|
43
43
|
if platform.system() == "Windows":
|
|
44
|
-
run_shell_script(r"""& "$HOME\.local\bin\uv.exe" tool install --upgrade "machineconfig>=6.
|
|
44
|
+
run_shell_script(r"""& "$HOME\.local\bin\uv.exe" tool install --upgrade "machineconfig>=6.61" """)
|
|
45
45
|
else:
|
|
46
|
-
run_shell_script("""$HOME/.local/bin/uv tool install --upgrade "machineconfig>=6.
|
|
46
|
+
run_shell_script("""$HOME/.local/bin/uv tool install --upgrade "machineconfig>=6.61" """)
|
|
47
47
|
from machineconfig.profile.create_shell_profile import create_default_shell_profile
|
|
48
48
|
if not no_copy_assets:
|
|
49
49
|
create_default_shell_profile() # involves copying assets too
|
|
@@ -68,7 +68,7 @@ def navigate():
|
|
|
68
68
|
path = Path(navigator.__file__).resolve().parent.joinpath("devops_navigator.py")
|
|
69
69
|
from machineconfig.utils.code import run_shell_script
|
|
70
70
|
if Path.home().joinpath("code/machineconfig").exists(): executable = f"""--project "{str(Path.home().joinpath("code/machineconfig"))}" --with textual"""
|
|
71
|
-
else: executable = """--with "machineconfig>=6.
|
|
71
|
+
else: executable = """--with "machineconfig>=6.61,textual" """
|
|
72
72
|
run_shell_script(f"""uv run {executable} {path}""")
|
|
73
73
|
|
|
74
74
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
3
|
import typer
|
|
4
|
-
from typing import Annotated, Optional
|
|
4
|
+
from typing import Annotated, Optional, TypedDict
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
import subprocess
|
|
7
7
|
import requests
|
|
@@ -115,3 +115,28 @@ def merge_pdfs(
|
|
|
115
115
|
from machineconfig.utils.code import run_shell_script, get_uv_command_executing_python_script
|
|
116
116
|
uv_command, _py_file = get_uv_command_executing_python_script(python_script=code, uv_with=["pypdf"], uv_project_dir=None)
|
|
117
117
|
run_shell_script(uv_command)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class MachineSpecs(TypedDict):
|
|
121
|
+
system: str
|
|
122
|
+
distro: str
|
|
123
|
+
home_dir: str
|
|
124
|
+
def get_machine_specs() -> MachineSpecs:
|
|
125
|
+
"""Write print and return the local machine specs."""
|
|
126
|
+
import platform
|
|
127
|
+
UV_RUN_CMD = "$HOME/.local/bin/uv run" if platform.system() != "Windows" else """& "$env:USERPROFILE/.local/bin/uv" run"""
|
|
128
|
+
command = f"""{UV_RUN_CMD} --with distro python -c "import distro; print(distro.name(pretty=True))" """
|
|
129
|
+
import subprocess
|
|
130
|
+
distro = subprocess.run(command, shell=True, capture_output=True, text=True).stdout.strip()
|
|
131
|
+
specs: MachineSpecs = {
|
|
132
|
+
"system": platform.system(),
|
|
133
|
+
"distro": distro,
|
|
134
|
+
"home_dir": str(Path.home()),
|
|
135
|
+
}
|
|
136
|
+
print(specs)
|
|
137
|
+
from machineconfig.utils.source_of_truth import CONFIG_ROOT
|
|
138
|
+
path = CONFIG_ROOT.joinpath("machine_specs.json")
|
|
139
|
+
CONFIG_ROOT.mkdir(parents=True, exist_ok=True)
|
|
140
|
+
import json
|
|
141
|
+
path.write_text(json.dumps(specs, indent=4), encoding="utf-8")
|
|
142
|
+
return specs
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# mkdir ~/data/local
|
|
6
6
|
# sudo mount -o nolock,noatime,nodiratime,proto=tcp,timeo=600,retrans=2,noac alex-p51s-5:/home/alex/data/local ./data/local
|
|
7
7
|
|
|
8
|
-
uv run --python 3.14 --with "machineconfig>=6.
|
|
8
|
+
uv run --python 3.14 --with "machineconfig>=6.61" python -m machineconfig.scripts.python.mount_nfs
|
|
9
9
|
# Check if remote server is reachable and share folder exists
|
|
10
10
|
if ! ping -c 1 "$remote_server" &> /dev/null; then
|
|
11
11
|
echo "💥 Error: Remote server $remote_server is not reachable."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
from machineconfig.scripts.python.helpers_devops.cli_utils import download, merge_pdfs
|
|
3
|
+
from machineconfig.scripts.python.helpers_devops.cli_utils import download, merge_pdfs, get_machine_specs
|
|
4
4
|
import typer
|
|
5
5
|
|
|
6
6
|
|
|
@@ -11,6 +11,8 @@ def get_app() -> typer.Typer:
|
|
|
11
11
|
app.command(name="d", no_args_is_help=True, hidden=True)(download)
|
|
12
12
|
app.command(name="merge-pdfs", no_args_is_help=True, help="[m] Merge two PDF files into one.")(merge_pdfs)
|
|
13
13
|
app.command(name="m", no_args_is_help=True, hidden=True)(merge_pdfs)
|
|
14
|
+
app.command(name="get-machine-specs", no_args_is_help=False, help="[g] Get machine specifications.")(get_machine_specs)
|
|
15
|
+
app.command(name="g", no_args_is_help=False, hidden=True)(get_machine_specs)
|
|
14
16
|
return app
|
|
15
17
|
|
|
16
18
|
|
|
@@ -7,7 +7,7 @@ $user = ''
|
|
|
7
7
|
$sharePath = ''
|
|
8
8
|
$driveLetter = ''
|
|
9
9
|
|
|
10
|
-
uv run --python 3.14 --with "machineconfig>=6.
|
|
10
|
+
uv run --python 3.14 --with "machineconfig>=6.61" python -m machineconfig.scripts.python.mount_ssh
|
|
11
11
|
|
|
12
12
|
net use T: \\sshfs.kr\$user@$host.local
|
|
13
13
|
# this worked: net use T: \\sshfs\alex@alex-p51s-5.local
|
|
@@ -34,10 +34,10 @@ Set-Alias -Name l -Value lsdla -Option AllScope
|
|
|
34
34
|
function d { devops @args }
|
|
35
35
|
function c { cloud @args }
|
|
36
36
|
function a { agents @args }
|
|
37
|
-
function
|
|
37
|
+
function ss { sessions @args }
|
|
38
38
|
function ff { ftpx @args }
|
|
39
39
|
function f { fire @args }
|
|
40
|
-
function
|
|
40
|
+
function rr { croshell @args }
|
|
41
41
|
function u { utils @args }
|
|
42
42
|
|
|
43
43
|
# try {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
. <( curl -sSL "https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_linux/uv.sh")
|
|
3
3
|
mcfg() {
|
|
4
|
-
"$HOME/.local/bin/uv" run --python 3.14 --with "machineconfig>=6.
|
|
4
|
+
"$HOME/.local/bin/uv" run --python 3.14 --with "machineconfig>=6.61" mcfg "$@"
|
|
5
5
|
}
|
|
6
6
|
alias d="mcfg devops"
|
|
7
7
|
alias c="mcfg cloud"
|
|
8
8
|
alias a="mcfg agents"
|
|
9
|
-
alias
|
|
9
|
+
alias ss="mcfg sessions"
|
|
10
10
|
alias ff="mcfg ftpx"
|
|
11
11
|
alias f="mcfg fire"
|
|
12
|
-
alias
|
|
12
|
+
alias rr="mcfg croshell"
|
|
13
13
|
alias u="mcfg utils"
|
|
14
14
|
echo "mcfg command is now defined in this shell session."
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
iex (iwr "https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_windows/uv.ps1").Content
|
|
4
4
|
function mcfg {
|
|
5
|
-
& "$HOME\.local\bin\uv.exe" run --python 3.14 --with "machineconfig>=6.
|
|
5
|
+
& "$HOME\.local\bin\uv.exe" run --python 3.14 --with "machineconfig>=6.61" mcfg $args
|
|
6
6
|
}
|
|
7
7
|
function d { mcfg devops @args }
|
|
8
8
|
function c { mcfg cloud @args }
|
|
9
9
|
function a { mcfg agents @args }
|
|
10
|
-
function
|
|
10
|
+
function ss { mcfg sessions @args }
|
|
11
11
|
function ff { mcfg ftpx @args }
|
|
12
12
|
function f { mcfg fire @args }
|
|
13
|
-
function
|
|
13
|
+
function rr { mcfg croshell @args }
|
|
14
14
|
function u { mcfg utils @args }
|
|
15
15
|
Write-Host "mcfg command aliases are now defined in this PowerShell session."
|
machineconfig/utils/ssh.py
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
from typing import Callable, Optional, Any, Union
|
|
1
|
+
from typing import Callable, Optional, Any, Union, cast
|
|
2
2
|
import os
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
import platform
|
|
5
|
+
from machineconfig.scripts.python.helpers_devops.cli_utils import MachineSpecs
|
|
5
6
|
import rich.console
|
|
6
|
-
from machineconfig.utils.terminal import Response
|
|
7
|
-
from machineconfig.utils.accessories import pprint
|
|
8
|
-
|
|
7
|
+
from machineconfig.utils.terminal import Response
|
|
8
|
+
from machineconfig.utils.accessories import pprint, randstr
|
|
9
|
+
from machineconfig.utils.meta import lambda_to_python_script
|
|
9
10
|
UV_RUN_CMD = "$HOME/.local/bin/uv run" if platform.system() != "Windows" else """& "$env:USERPROFILE/.local/bin/uv" run"""
|
|
10
|
-
MACHINECONFIG_VERSION = "machineconfig>=6.
|
|
11
|
+
MACHINECONFIG_VERSION = "machineconfig>=6.61"
|
|
11
12
|
DEFAULT_PICKLE_SUBDIR = "tmp_results/tmp_scripts/ssh"
|
|
12
13
|
|
|
13
|
-
|
|
14
14
|
class SSH:
|
|
15
15
|
def __init__(
|
|
16
16
|
self, host: Optional[str], username: Optional[str], hostname: Optional[str], ssh_key_path: Optional[str], password: Optional[str], port: int, enable_compression: bool):
|
|
@@ -22,7 +22,6 @@ class SSH:
|
|
|
22
22
|
self.username: str
|
|
23
23
|
self.port: int = port
|
|
24
24
|
self.proxycommand: Optional[str] = None
|
|
25
|
-
import platform
|
|
26
25
|
import paramiko # type: ignore
|
|
27
26
|
import getpass
|
|
28
27
|
|
|
@@ -109,13 +108,15 @@ class SSH:
|
|
|
109
108
|
def view_bar(self, transferred: int, total: int) -> None:
|
|
110
109
|
if self.progress and self.task is not None:
|
|
111
110
|
self.progress.update(self.task, completed=transferred, total=total)
|
|
112
|
-
|
|
113
111
|
self.tqdm_wrap = RichProgressWrapper
|
|
114
|
-
|
|
115
|
-
self.
|
|
116
|
-
self.
|
|
112
|
+
from machineconfig.scripts.python.helpers_devops.cli_utils import get_machine_specs
|
|
113
|
+
self.local_specs: MachineSpecs = get_machine_specs()
|
|
114
|
+
resp = self.run_shell(command=f"""~/.local/bin/utils get-machine-specs """, verbose_output=False, description="Getting remote machine specs", strict_stderr=False, strict_return_code=False)
|
|
115
|
+
import json
|
|
116
|
+
json_str = resp.op
|
|
117
|
+
print(f"Remote machine specs JSON: {resp}")
|
|
118
|
+
self.remote_specs: MachineSpecs = cast(MachineSpecs, json.loads(json_str))
|
|
117
119
|
self.terminal_responses: list[Response] = []
|
|
118
|
-
self.platform = platform
|
|
119
120
|
|
|
120
121
|
def __enter__(self) -> "SSH":
|
|
121
122
|
return self
|
|
@@ -126,34 +127,11 @@ class SSH:
|
|
|
126
127
|
self.sftp.close()
|
|
127
128
|
self.sftp = None
|
|
128
129
|
self.ssh.close()
|
|
129
|
-
def get_remote_machine(self) -> MACHINE:
|
|
130
|
-
if self._remote_machine is None:
|
|
131
|
-
windows_test1 = self.run_shell(command="$env:OS", verbose_output=False, description="Testing Remote OS Type", strict_stderr=False, strict_return_code=False).op
|
|
132
|
-
windows_test2 = self.run_shell(command="echo %OS%", verbose_output=False, description="Testing Remote OS Type Again", strict_stderr=False, strict_return_code=False).op
|
|
133
|
-
if windows_test1 == "Windows_NT" or windows_test2 == "Windows_NT":
|
|
134
|
-
self._remote_machine = "Windows"
|
|
135
|
-
else:
|
|
136
|
-
self._remote_machine = "Linux"
|
|
137
|
-
return self._remote_machine
|
|
138
|
-
def get_local_distro(self) -> str:
|
|
139
|
-
if self._local_distro is None:
|
|
140
|
-
command = f"""{UV_RUN_CMD} --with distro python -c "import distro; print(distro.name(pretty=True))" """
|
|
141
|
-
import subprocess
|
|
142
|
-
res = subprocess.run(command, shell=True, capture_output=True, text=True).stdout.strip()
|
|
143
|
-
self._local_distro = res
|
|
144
|
-
return res
|
|
145
|
-
return self._local_distro
|
|
146
|
-
def get_remote_distro(self) -> str:
|
|
147
|
-
if self._remote_distro is None:
|
|
148
|
-
command_str = f"""{UV_RUN_CMD} --with distro python -c "import distro; print(distro.name(pretty=True))" """
|
|
149
|
-
res = self.run_shell(command=command_str, verbose_output=True, description="", strict_stderr=False, strict_return_code=False)
|
|
150
|
-
self._remote_distro = res.op_if_successfull_or_default() or ""
|
|
151
|
-
return self._remote_distro
|
|
152
130
|
def restart_computer(self) -> Response:
|
|
153
|
-
return self.run_shell(command="Restart-Computer -Force" if self.
|
|
131
|
+
return self.run_shell(command="Restart-Computer -Force" if self.remote_specs["system"] == "Windows" else "sudo reboot", verbose_output=True, description="", strict_stderr=False, strict_return_code=False)
|
|
154
132
|
def send_ssh_key(self) -> Response:
|
|
155
|
-
self.copy_from_here(source_path=
|
|
156
|
-
if self.
|
|
133
|
+
self.copy_from_here(source_path="~/.ssh/id_rsa.pub", target_rel2home=None, compress_with_zip=False, recursive=False, overwrite_existing=False)
|
|
134
|
+
if self.remote_specs["system"] != "Windows":
|
|
157
135
|
raise RuntimeError("send_ssh_key is only supported for Windows remote machines")
|
|
158
136
|
code_url = "https://raw.githubusercontent.com/thisismygitrepo/machineconfig/refs/heads/main/src/machineconfig/setup_windows/openssh-server_add-sshkey.ps1"
|
|
159
137
|
import urllib.request
|
|
@@ -162,17 +140,17 @@ class SSH:
|
|
|
162
140
|
return self.run_shell(command=code, verbose_output=True, description="", strict_stderr=False, strict_return_code=False)
|
|
163
141
|
|
|
164
142
|
def get_remote_repr(self, add_machine: bool = False) -> str:
|
|
165
|
-
return f"{self.username}@{self.hostname}:{self.port}" + (f" [{self.
|
|
143
|
+
return f"{self.username}@{self.hostname}:{self.port}" + (f" [{self.remote_specs['system']}][{self.remote_specs['distro']}]" if add_machine else "")
|
|
166
144
|
def get_local_repr(self, add_machine: bool = False) -> str:
|
|
167
145
|
import getpass
|
|
168
|
-
return f"{getpass.getuser()}@{
|
|
146
|
+
return f"{getpass.getuser()}@{platform.node()}" + (f" [{platform.system()}][{self.local_specs['distro']}]" if add_machine else "")
|
|
169
147
|
def get_ssh_conn_str(self, command: str) -> str:
|
|
170
148
|
return "ssh " + (f" -i {self.ssh_key_path}" if self.ssh_key_path else "") + self.get_remote_repr(add_machine=False).replace(":", " -p ") + (f" -t {command} " if command != "" else " ")
|
|
171
149
|
def __repr__(self) -> str:
|
|
172
150
|
return f"local {self.get_local_repr(add_machine=True)} >>> SSH TO >>> remote {self.get_remote_repr(add_machine=True)}"
|
|
173
151
|
|
|
174
152
|
def run_locally(self, command: str) -> Response:
|
|
175
|
-
print(f"""💻 [LOCAL EXECUTION] Running command on node: {self.
|
|
153
|
+
print(f"""💻 [LOCAL EXECUTION] Running command on node: {self.local_specs['system']} Command: {command}""")
|
|
176
154
|
res = Response(cmd=command)
|
|
177
155
|
res.output.returncode = os.system(command)
|
|
178
156
|
return res
|
|
@@ -184,15 +162,14 @@ class SSH:
|
|
|
184
162
|
res.print()
|
|
185
163
|
else:
|
|
186
164
|
res.capture().print_if_unsuccessful(desc=description, strict_err=strict_stderr, strict_returncode=strict_return_code, assert_success=False)
|
|
187
|
-
self.terminal_responses.append(res)
|
|
165
|
+
# self.terminal_responses.append(res)
|
|
188
166
|
return res
|
|
189
167
|
def run_py(self, python_code: str, uv_with: Optional[list[str]], uv_project_dir: Optional[str],
|
|
190
168
|
description: str, verbose_output: bool, strict_stderr: bool, strict_return_code: bool) -> Response:
|
|
191
|
-
from machineconfig.utils.accessories import randstr
|
|
192
169
|
py_path = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/runpy_{randstr()}.py")
|
|
193
170
|
py_path.parent.mkdir(parents=True, exist_ok=True)
|
|
194
171
|
py_path.write_text(python_code, encoding="utf-8")
|
|
195
|
-
self.copy_from_here(source_path=py_path,
|
|
172
|
+
self.copy_from_here(source_path=str(py_path), target_rel2home=None, compress_with_zip=False, recursive=False, overwrite_existing=False)
|
|
196
173
|
if uv_with is not None and len(uv_with) > 0:
|
|
197
174
|
with_clause = " --with " + '"' + ",".join(uv_with) + '"'
|
|
198
175
|
else:
|
|
@@ -205,8 +182,7 @@ class SSH:
|
|
|
205
182
|
return self.run_shell(command=uv_cmd, verbose_output=verbose_output, description=description or f"run_py on {self.get_remote_repr(add_machine=False)}", strict_stderr=strict_stderr, strict_return_code=strict_return_code)
|
|
206
183
|
|
|
207
184
|
def run_py_func(self, func: Callable[..., Any], uv_with: Optional[list[str]], uv_project_dir: Optional[str]) -> Response:
|
|
208
|
-
|
|
209
|
-
command = lambda_to_python_script(lmb=lambda: func, in_global=True)
|
|
185
|
+
command = lambda_to_python_script(lmb=func, in_global=True)
|
|
210
186
|
return self.run_py(python_code=command, uv_with=uv_with, uv_project_dir=uv_project_dir,
|
|
211
187
|
description=f"run_py_func {func.__name__} on {self.get_remote_repr(add_machine=False)}",
|
|
212
188
|
verbose_output=True, strict_stderr=True, strict_return_code=True)
|
|
@@ -218,77 +194,45 @@ class SSH:
|
|
|
218
194
|
local_path.parent.mkdir(parents=True, exist_ok=True)
|
|
219
195
|
self.sftp.get(remotepath=remote_path, localpath=str(local_path))
|
|
220
196
|
|
|
221
|
-
def
|
|
197
|
+
def create_dir(self, path_rel2home: str, overwrite_existing: bool) -> None:
|
|
222
198
|
"""Helper to create a directory on remote machine and return its path."""
|
|
223
|
-
def create_target_dir(
|
|
199
|
+
def create_target_dir(target_rel2home: str, overwrite: bool) -> None:
|
|
224
200
|
from pathlib import Path
|
|
225
201
|
import shutil
|
|
226
|
-
|
|
227
|
-
directory_path = Path(target_dir_path).expanduser()
|
|
202
|
+
directory_path = Path(target_rel2home).expanduser()
|
|
228
203
|
if overwrite and directory_path.exists():
|
|
229
204
|
if directory_path.is_dir():
|
|
230
205
|
shutil.rmtree(directory_path)
|
|
231
206
|
else:
|
|
232
207
|
directory_path.unlink()
|
|
233
208
|
directory_path.parent.mkdir(parents=True, exist_ok=True)
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
from machineconfig.utils.accessories import randstr
|
|
242
|
-
remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
|
|
243
|
-
# command = function_to_script(func=create_target_dir, call_with_kwargs={"target_dir_path": Path(target_path).as_posix(), "overwrite": overwrite_existing, "json_output_path": remote_json_output})
|
|
244
|
-
command = lambda_to_python_script(lmb=lambda: create_target_dir(target_dir_path=str(target_path), overwrite=overwrite_existing, json_output_path=remote_json_output), in_global=True)
|
|
245
|
-
response = self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None,
|
|
246
|
-
description=f"Creating target directory `{Path(target_path).parent.as_posix()}` @ {self.get_remote_repr(add_machine=False)}",
|
|
247
|
-
verbose_output=False, strict_stderr=False, strict_return_code=False)
|
|
248
|
-
remote_json_path = response.op.strip()
|
|
249
|
-
if not remote_json_path:
|
|
250
|
-
raise RuntimeError(f"Failed to create target directory {target_path} - no response from remote")
|
|
251
|
-
from machineconfig.utils.accessories import randstr
|
|
252
|
-
local_json = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/local_{randstr()}.json")
|
|
253
|
-
self._simple_sftp_get(remote_path=remote_json_path, local_path=local_json)
|
|
254
|
-
import json
|
|
255
|
-
try:
|
|
256
|
-
result = json.loads(local_json.read_text(encoding="utf-8"))
|
|
257
|
-
except (json.JSONDecodeError, FileNotFoundError) as err:
|
|
258
|
-
raise RuntimeError(f"Failed to create target directory {target_path} - invalid JSON response: {err}") from err
|
|
259
|
-
finally:
|
|
260
|
-
if local_json.exists():
|
|
261
|
-
local_json.unlink()
|
|
262
|
-
assert isinstance(result, str), f"Failed to create target directory {target_path} on remote"
|
|
263
|
-
return result
|
|
264
|
-
|
|
209
|
+
return
|
|
210
|
+
command = lambda_to_python_script(lmb=lambda: create_target_dir(target_rel2home=path_rel2home, overwrite=overwrite_existing), in_global=True)
|
|
211
|
+
tmp_py_file = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/create_target_dir_{randstr()}.py")
|
|
212
|
+
tmp_py_file.parent.mkdir(parents=True, exist_ok=True)
|
|
213
|
+
tmp_py_file.write_text(command, encoding="utf-8")
|
|
214
|
+
self.copy_from_here(source_path=str(tmp_py_file), target_rel2home=None, compress_with_zip=False, recursive=False, overwrite_existing=True)
|
|
215
|
+
self.run_shell(command=f"""{UV_RUN_CMD} python {tmp_py_file.as_posix()}""", verbose_output=False, description=f"Creating target dir {path_rel2home}", strict_stderr=True, strict_return_code=True)
|
|
265
216
|
|
|
266
|
-
def copy_from_here(self, source_path:
|
|
267
|
-
if self.sftp is None:
|
|
268
|
-
raise RuntimeError(f"SFTP connection not available for {self.hostname}. Cannot transfer files.")
|
|
269
|
-
|
|
217
|
+
def copy_from_here(self, source_path: str, target_rel2home: Optional[str], compress_with_zip: bool, recursive: bool, overwrite_existing: bool) -> None:
|
|
218
|
+
if self.sftp is None: raise RuntimeError(f"SFTP connection not available for {self.hostname}. Cannot transfer files.")
|
|
270
219
|
source_obj = Path(source_path).expanduser().absolute()
|
|
271
|
-
if not source_obj.exists():
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if target_path is None:
|
|
275
|
-
try:
|
|
276
|
-
target_path_relative = source_obj.relative_to(Path.home())
|
|
277
|
-
target_path = Path("~") / target_path_relative
|
|
220
|
+
if not source_obj.exists(): raise RuntimeError(f"SSH Error: source `{source_obj}` does not exist!")
|
|
221
|
+
if target_rel2home is None:
|
|
222
|
+
try: target_rel2home = str(source_obj.relative_to(Path.home()))
|
|
278
223
|
except ValueError:
|
|
279
224
|
raise RuntimeError(f"If target is not specified, source must be relative to home directory, but got: {source_obj}")
|
|
280
|
-
|
|
281
225
|
if not compress_with_zip and source_obj.is_dir():
|
|
282
226
|
if not recursive:
|
|
283
227
|
raise RuntimeError(f"SSH Error: source `{source_obj}` is a directory! Set `recursive=True` for recursive sending or `compress_with_zip=True` to zip it first.")
|
|
284
228
|
file_paths_to_upload: list[Path] = [file_path for file_path in source_obj.rglob("*") if file_path.is_file()]
|
|
285
|
-
|
|
229
|
+
# self.create_dir(path_rel2home=target_rel2home, overwrite_existing=overwrite_existing)
|
|
286
230
|
for idx, file_path in enumerate(file_paths_to_upload):
|
|
287
231
|
print(f" {idx + 1:03d}. {file_path}")
|
|
288
232
|
for file_path in file_paths_to_upload:
|
|
289
|
-
remote_file_target = Path(
|
|
290
|
-
self.copy_from_here(source_path=file_path,
|
|
291
|
-
return
|
|
233
|
+
remote_file_target = Path(target_rel2home).joinpath(file_path.relative_to(source_obj))
|
|
234
|
+
self.copy_from_here(source_path=str(file_path), target_rel2home=str(remote_file_target), compress_with_zip=False, recursive=False, overwrite_existing=overwrite_existing)
|
|
235
|
+
return None
|
|
292
236
|
if compress_with_zip:
|
|
293
237
|
print("🗜️ ZIPPING ...")
|
|
294
238
|
import shutil
|
|
@@ -298,16 +242,14 @@ class SSH:
|
|
|
298
242
|
else:
|
|
299
243
|
shutil.make_archive(str(zip_path), "zip", source_obj.parent, source_obj.name)
|
|
300
244
|
source_obj = Path(str(zip_path) + ".zip")
|
|
301
|
-
if not
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
remotepath = Path(remotepath_str)
|
|
305
|
-
print(f"""📤 [SFTP UPLOAD] Sending file: {repr(source_obj)} ==> Remote Path: {remotepath.as_posix()}""")
|
|
245
|
+
if not target_rel2home.endswith(".zip"): target_rel2home = target_rel2home + ".zip"
|
|
246
|
+
# remotepath_str = self.create_dir(target_path=target_path, overwrite_existing=overwrite_existing)
|
|
247
|
+
print(f"""📤 [SFTP UPLOAD] Sending file: {repr(source_obj)} ==> Remote Path: {target_rel2home}""")
|
|
306
248
|
try:
|
|
307
249
|
with self.tqdm_wrap(ascii=True, unit="b", unit_scale=True) as pbar:
|
|
308
250
|
if self.sftp is None: # type: ignore[unreachable]
|
|
309
251
|
raise RuntimeError(f"SFTP connection lost for {self.hostname}")
|
|
310
|
-
self.sftp.put(localpath=str(source_obj), remotepath=
|
|
252
|
+
self.sftp.put(localpath=str(source_obj), remotepath=str(Path(self.remote_specs["home_dir"]).joinpath(target_rel2home)), callback=pbar.view_bar)
|
|
311
253
|
except Exception:
|
|
312
254
|
if compress_with_zip and source_obj.exists() and str(source_obj).endswith("_archive.zip"):
|
|
313
255
|
source_obj.unlink()
|
|
@@ -325,11 +267,14 @@ class SSH:
|
|
|
325
267
|
with zipfile.ZipFile(archive_path, "r") as archive_handle:
|
|
326
268
|
archive_handle.extractall(extraction_directory)
|
|
327
269
|
archive_path.unlink()
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
270
|
+
command = lambda_to_python_script(lmb=lambda: unzip_archive(zip_file_path=str(Path(self.remote_specs["home_dir"]).joinpath(target_rel2home)), overwrite_flag=overwrite_existing), in_global=True)
|
|
271
|
+
tmp_py_file = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/create_target_dir_{randstr()}.py")
|
|
272
|
+
tmp_py_file.parent.mkdir(parents=True, exist_ok=True)
|
|
273
|
+
tmp_py_file.write_text(command, encoding="utf-8")
|
|
274
|
+
transferred_py_file = self.copy_from_here(source_path=str(tmp_py_file), target_rel2home=None, compress_with_zip=True, recursive=False, overwrite_existing=True)
|
|
275
|
+
self.run_shell(command=f"""{UV_RUN_CMD} python {transferred_py_file}""", verbose_output=False, description=f"UNZIPPING {target_rel2home}", strict_stderr=True, strict_return_code=True)
|
|
331
276
|
source_obj.unlink()
|
|
332
|
-
return
|
|
277
|
+
return None
|
|
333
278
|
|
|
334
279
|
def _check_remote_is_dir(self, source_path: Union[str, Path]) -> bool:
|
|
335
280
|
"""Helper to check if a remote path is a directory."""
|
|
@@ -342,16 +287,13 @@ class SSH:
|
|
|
342
287
|
json_result_path.write_text(json.dumps(is_directory, indent=2), encoding="utf-8")
|
|
343
288
|
print(json_result_path.as_posix())
|
|
344
289
|
return is_directory
|
|
345
|
-
|
|
346
|
-
from machineconfig.utils.meta import lambda_to_python_script
|
|
347
|
-
from machineconfig.utils.accessories import randstr
|
|
348
290
|
remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
|
|
349
291
|
command = lambda_to_python_script(lmb=lambda: check_is_dir(path_to_check=str(source_path), json_output_path=remote_json_output), in_global=True)
|
|
350
292
|
response = self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None, description=f"Check if source `{source_path}` is a dir", verbose_output=False, strict_stderr=False, strict_return_code=False)
|
|
351
293
|
remote_json_path = response.op.strip()
|
|
352
294
|
if not remote_json_path:
|
|
353
295
|
raise RuntimeError(f"Failed to check if {source_path} is directory - no response from remote")
|
|
354
|
-
|
|
296
|
+
|
|
355
297
|
local_json = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/local_{randstr()}.json")
|
|
356
298
|
self._simple_sftp_get(remote_path=remote_json_path, local_path=local_json)
|
|
357
299
|
import json
|
|
@@ -377,15 +319,15 @@ class SSH:
|
|
|
377
319
|
print(json_result_path.as_posix())
|
|
378
320
|
return expanded_path_posix
|
|
379
321
|
|
|
380
|
-
|
|
381
|
-
|
|
322
|
+
|
|
323
|
+
|
|
382
324
|
remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
|
|
383
325
|
command = lambda_to_python_script(lmb=lambda: expand_source(path_to_expand=str(source_path), json_output_path=remote_json_output), in_global=True)
|
|
384
326
|
response = self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None, description="Resolving source path by expanding user", verbose_output=False, strict_stderr=False, strict_return_code=False)
|
|
385
327
|
remote_json_path = response.op.strip()
|
|
386
328
|
if not remote_json_path:
|
|
387
329
|
raise RuntimeError(f"Could not resolve source path {source_path} - no response from remote")
|
|
388
|
-
|
|
330
|
+
|
|
389
331
|
local_json = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/local_{randstr()}.json")
|
|
390
332
|
self._simple_sftp_get(remote_path=remote_json_path, local_path=local_json)
|
|
391
333
|
import json
|
|
@@ -426,15 +368,15 @@ class SSH:
|
|
|
426
368
|
print(json_result_path.as_posix())
|
|
427
369
|
return file_paths_list
|
|
428
370
|
|
|
429
|
-
|
|
430
|
-
|
|
371
|
+
|
|
372
|
+
|
|
431
373
|
remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
|
|
432
374
|
command = lambda_to_python_script(lmb=lambda: search_files(directory_path=expanded_source, json_output_path=remote_json_output), in_global=True)
|
|
433
375
|
response = self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None, description="Searching for files in source", verbose_output=False, strict_stderr=False, strict_return_code=False)
|
|
434
376
|
remote_json_path = response.op.strip()
|
|
435
377
|
if not remote_json_path:
|
|
436
378
|
raise RuntimeError(f"Could not resolve source path {source} - no response from remote")
|
|
437
|
-
|
|
379
|
+
|
|
438
380
|
local_json = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/local_{randstr()}.json")
|
|
439
381
|
self._simple_sftp_get(remote_path=remote_json_path, local_path=local_json)
|
|
440
382
|
import json
|
|
@@ -464,15 +406,15 @@ class SSH:
|
|
|
464
406
|
except ValueError:
|
|
465
407
|
raise RuntimeError(f"Source path must be relative to home directory: {source_absolute_path}")
|
|
466
408
|
|
|
467
|
-
|
|
468
|
-
|
|
409
|
+
|
|
410
|
+
|
|
469
411
|
remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
|
|
470
412
|
command = lambda_to_python_script(lmb=lambda: collapse_to_home_dir(absolute_path=expanded_source, json_output_path=remote_json_output), in_global=True)
|
|
471
413
|
response = self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None, description="Finding default target via relative source path", verbose_output=False, strict_stderr=False, strict_return_code=False)
|
|
472
414
|
remote_json_path_dir = response.op.strip()
|
|
473
415
|
if not remote_json_path_dir:
|
|
474
416
|
raise RuntimeError("Could not resolve target path - no response from remote")
|
|
475
|
-
|
|
417
|
+
|
|
476
418
|
local_json_dir = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/local_{randstr()}.json")
|
|
477
419
|
self._simple_sftp_get(remote_path=remote_json_path_dir, local_path=local_json_dir)
|
|
478
420
|
import json
|
|
@@ -516,15 +458,15 @@ class SSH:
|
|
|
516
458
|
print(json_result_path.as_posix())
|
|
517
459
|
return zip_file_path
|
|
518
460
|
|
|
519
|
-
|
|
520
|
-
|
|
461
|
+
|
|
462
|
+
|
|
521
463
|
remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
|
|
522
464
|
command = lambda_to_python_script(lmb=lambda: zip_source(path_to_zip=expanded_source, json_output_path=remote_json_output), in_global=True)
|
|
523
465
|
response = self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None, description=f"Zipping source file {source}", verbose_output=False, strict_stderr=False, strict_return_code=False)
|
|
524
466
|
remote_json_path = response.op.strip()
|
|
525
467
|
if not remote_json_path:
|
|
526
468
|
raise RuntimeError(f"Could not zip {source} - no response from remote")
|
|
527
|
-
|
|
469
|
+
|
|
528
470
|
local_json = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/local_{randstr()}.json")
|
|
529
471
|
self._simple_sftp_get(remote_path=remote_json_path, local_path=local_json)
|
|
530
472
|
import json
|
|
@@ -555,15 +497,15 @@ class SSH:
|
|
|
555
497
|
except ValueError:
|
|
556
498
|
raise RuntimeError(f"Source path must be relative to home directory: {source_absolute_path}")
|
|
557
499
|
|
|
558
|
-
|
|
559
|
-
|
|
500
|
+
|
|
501
|
+
|
|
560
502
|
remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
|
|
561
503
|
command = lambda_to_python_script(lmb=lambda: collapse_to_home(absolute_path=expanded_source, json_output_path=remote_json_output), in_global=True)
|
|
562
504
|
response = self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None, description="Finding default target via relative source path", verbose_output=False, strict_stderr=False, strict_return_code=False)
|
|
563
505
|
remote_json_path = response.op.strip()
|
|
564
506
|
if not remote_json_path:
|
|
565
507
|
raise RuntimeError("Could not resolve target path - no response from remote")
|
|
566
|
-
|
|
508
|
+
|
|
567
509
|
local_json = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/local_{randstr()}.json")
|
|
568
510
|
self._simple_sftp_get(remote_path=remote_json_path, local_path=local_json)
|
|
569
511
|
import json
|
|
@@ -613,10 +555,12 @@ class SSH:
|
|
|
613
555
|
else:
|
|
614
556
|
file_or_dir_path.unlink()
|
|
615
557
|
|
|
616
|
-
|
|
558
|
+
|
|
617
559
|
command = lambda_to_python_script(lmb=lambda: delete_temp_zip(path_to_delete=expanded_source), in_global=True)
|
|
618
560
|
self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None, description="Cleaning temp zip files @ remote.", verbose_output=False, strict_stderr=True, strict_return_code=True)
|
|
619
561
|
|
|
620
562
|
print("\n")
|
|
621
563
|
return target_obj
|
|
622
564
|
|
|
565
|
+
if __name__ == "__main__":
|
|
566
|
+
ssh = SSH(host="p51s", username=None, hostname=None, ssh_key_path=None, password=None, port=22, enable_compression=False)
|
machineconfig/utils/terminal.py
CHANGED
|
@@ -35,7 +35,8 @@ class Response:
|
|
|
35
35
|
def __call__(self, *args: Any, **kwargs: Any) -> Optional[str]:
|
|
36
36
|
_ = args, kwargs
|
|
37
37
|
return self.op.rstrip() if type(self.op) is str else None
|
|
38
|
-
|
|
38
|
+
def __repr__(self) -> str:
|
|
39
|
+
return f"Response({self.input=}, {self.output=}, {self.desc=}, {self.op=}, {self.ip=}, {self.err=}, {self.returncode=})"
|
|
39
40
|
@property
|
|
40
41
|
def op(self) -> str:
|
|
41
42
|
return self.output.stdout
|
|
@@ -97,115 +98,3 @@ class Response:
|
|
|
97
98
|
txt = tmp1 + Text(str(self.input), style="white") + tmp2 + Text("\n".join(list_str), style="white")
|
|
98
99
|
con.print(Panel(txt, title=f"🖥️ {self.desc}", subtitle=f"📋 {desc}", width=150, style="bold cyan on black"))
|
|
99
100
|
return self
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
'''
|
|
103
|
-
class Terminal:
|
|
104
|
-
def __init__(self, stdout: Optional[int] = subprocess.PIPE, stderr: Optional[int] = subprocess.PIPE, stdin: Optional[int] = subprocess.PIPE, elevated: bool = False):
|
|
105
|
-
self.machine: str = platform.system()
|
|
106
|
-
self.elevated: bool = elevated
|
|
107
|
-
self.stdout = stdout
|
|
108
|
-
self.stderr = stderr
|
|
109
|
-
self.stdin = stdin
|
|
110
|
-
|
|
111
|
-
# def set_std_system(self): self.stdout = sys.stdout; self.stderr = sys.stderr; self.stdin = sys.stdin
|
|
112
|
-
# def set_std_pipe(self):
|
|
113
|
-
# self.stdout = subprocess.PIPE
|
|
114
|
-
# self.stderr = subprocess.PIPE
|
|
115
|
-
# self.stdin = subprocess.PIPE
|
|
116
|
-
|
|
117
|
-
# def set_std_null(self):
|
|
118
|
-
# self.stdout, self.stderr, self.stdin = subprocess.DEVNULL, subprocess.DEVNULL, subprocess.DEVNULL # Equivalent to `echo 'foo' &> /dev/null`
|
|
119
|
-
|
|
120
|
-
def run(self, *cmds: str, shell: Optional[SHELLS] = "default", check: bool = False, ip: Optional[str] = None) -> Response: # Runs SYSTEM commands like subprocess.run
|
|
121
|
-
"""Blocking operation. Thus, if you start a shell via this method, it will run in the main and won't stop until you exit manually IF stdin is set to sys.stdin, otherwise it will run and close quickly. Other combinations of stdin, stdout can lead to funny behaviour like no output but accept input or opposite.
|
|
122
|
-
* This method is short for: res = subprocess.run("powershell command", capture_output=True, shell=True, text=True) and unlike os.system(cmd), subprocess.run(cmd) gives much more control over the output and input.
|
|
123
|
-
* `shell=True` loads up the profile of the shell called so more specific commands can be run. Importantly, on Windows, the `start` command becomes availalbe and new windows can be launched.
|
|
124
|
-
* `capture_output` prevents the stdout to redirect to the stdout of the script automatically, instead it will be stored in the Response object returned. # `capture_output=True` same as `stdout=subprocess.PIPE, stderr=subprocess.PIPE`"""
|
|
125
|
-
my_list = list(
|
|
126
|
-
cmds
|
|
127
|
-
) # `subprocess.Popen` (process open) is the most general command. Used here to create asynchronous job. `subprocess.run` is a thin wrapper around Popen that makes it wait until it finishes the task. `suprocess.call` is an archaic command for pre-Python-3.5.
|
|
128
|
-
if self.machine == "Windows" and shell in {"powershell", "pwsh"}:
|
|
129
|
-
my_list = [shell, "-Command"] + my_list # alternatively, one can run "cmd"
|
|
130
|
-
if self.elevated is False or self.is_user_admin():
|
|
131
|
-
resp: subprocess.CompletedProcess[str] = subprocess.run(my_list, stderr=self.stderr, stdin=self.stdin, stdout=self.stdout, text=True, shell=True, check=check, input=ip)
|
|
132
|
-
else:
|
|
133
|
-
resp = __import__("ctypes").windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
|
|
134
|
-
return Response.from_completed_process(resp)
|
|
135
|
-
@staticmethod
|
|
136
|
-
def is_user_admin() -> bool: # adopted from: https://stackoverflow.com/questions/19672352/how-to-run-script-with-elevated-privilege-on-windows"""
|
|
137
|
-
if os.name == "nt":
|
|
138
|
-
try:
|
|
139
|
-
return __import__("ctypes").windll.shell32.IsUserAnAdmin()
|
|
140
|
-
except Exception:
|
|
141
|
-
import traceback
|
|
142
|
-
|
|
143
|
-
traceback.print_exc()
|
|
144
|
-
print("Admin check failed, assuming not an admin.")
|
|
145
|
-
return False
|
|
146
|
-
else:
|
|
147
|
-
return os.getuid() == 0 # Check for root on Posix
|
|
148
|
-
'''
|
|
149
|
-
|
|
150
|
-
# def run_shell_script(self, script: str, shell: SHELLS = "default", verbose: bool = False):
|
|
151
|
-
# if self.machine == "Linux":
|
|
152
|
-
# script = "#!/bin/bash" + "\n" + script # `source` is only available in bash.
|
|
153
|
-
# script_file = PathExtended.tmpfile(name="tmp_shell_script", suffix=".ps1" if self.machine == "Windows" else ".sh", folder="tmp_scripts")
|
|
154
|
-
# script_file.write_text(script, newline={"Windows": None, "Linux": "\n"}[self.machine])
|
|
155
|
-
# if shell == "default":
|
|
156
|
-
# if self.machine == "Windows":
|
|
157
|
-
# start_cmd = "powershell" # default shell on Windows is cmd which is not very useful. (./source is not available)
|
|
158
|
-
# full_command: Union[list[str], str] = [start_cmd, str(script_file)] # shell=True will cause this to be a string anyway (with space separation)
|
|
159
|
-
# else:
|
|
160
|
-
# start_cmd = "bash"
|
|
161
|
-
# full_command = f"{start_cmd} {script_file}" # full_command = [start_cmd, str(script_file)]
|
|
162
|
-
# else:
|
|
163
|
-
# full_command = f"{shell} {script_file}" # full_command = [shell, str(tmp_file)]
|
|
164
|
-
# if verbose:
|
|
165
|
-
# desc = "Script to be executed:"
|
|
166
|
-
# if platform.system() == "Windows":
|
|
167
|
-
# lexer = "powershell"
|
|
168
|
-
# elif platform.system() == "Linux":
|
|
169
|
-
# lexer = "sh"
|
|
170
|
-
# elif platform.system() == "Darwin":
|
|
171
|
-
# lexer = "sh" # macOS uses similar shell to Linux
|
|
172
|
-
# else:
|
|
173
|
-
# raise NotImplementedError(f"Platform {platform.system()} not supported.")
|
|
174
|
-
# from rich.console import Console
|
|
175
|
-
# from rich.panel import Panel
|
|
176
|
-
# from rich.syntax import Syntax
|
|
177
|
-
# import rich.progress as pb
|
|
178
|
-
|
|
179
|
-
# console = Console()
|
|
180
|
-
# console.print(Panel(Syntax(code=script, lexer=lexer), title=f"📄 {desc}"), style="bold red")
|
|
181
|
-
# with pb.Progress(transient=True) as progress:
|
|
182
|
-
# _task = progress.add_task(f"Running Script @ {script_file}", total=None)
|
|
183
|
-
# resp = subprocess.run(full_command, stderr=self.stderr, stdin=self.stdin, stdout=self.stdout, text=True, shell=True, check=False)
|
|
184
|
-
# else:
|
|
185
|
-
# resp = subprocess.run(full_command, stderr=self.stderr, stdin=self.stdin, stdout=self.stdout, text=True, shell=True, check=False)
|
|
186
|
-
# return Response.from_completed_process(resp)
|
|
187
|
-
|
|
188
|
-
# def run_py(self, script: str, wdir: OPLike = None, interactive: bool = True, ipython: bool = True, shell: Optional[str] = None, terminal: str = "", new_window: bool = True, header: bool = True): # async run, since sync run is meaningless.
|
|
189
|
-
# script = (Terminal.get_header(wdir=wdir, toolbox=True) if header else "") + script + ("\nDisplayData.set_pandas_auto_width()\n" if terminal in {"wt", "powershell", "pwsh"} else "")
|
|
190
|
-
# py_script = PathExtended.tmpfile(name="tmp_python_script", suffix=".py", folder="tmp_scripts/terminal")
|
|
191
|
-
# py_script.write_text(f"""print(r'''{script}''')""" + "\n" + script)
|
|
192
|
-
# print(f"""🚀 [ASYNC PYTHON SCRIPT] Script URI:
|
|
193
|
-
# {py_script.absolute().as_uri()}""")
|
|
194
|
-
# print("Script to be executed asyncronously: ", py_script.absolute().as_uri())
|
|
195
|
-
# shell_script = f"""
|
|
196
|
-
# {f"cd {wdir}" if wdir is not None else ""}
|
|
197
|
-
# {"ipython" if ipython else "python"} {"-i" if interactive else ""} {py_script}
|
|
198
|
-
# """
|
|
199
|
-
# shell_path = PathExtended.tmpfile(name="tmp_shell_script", suffix=".sh" if self.machine == "Linux" else ".ps1", folder="tmp_scripts/shell")
|
|
200
|
-
# shell_path.write_text(shell_script)
|
|
201
|
-
# if shell is None and self.machine == "Windows":
|
|
202
|
-
# shell = "pwsh"
|
|
203
|
-
# window = "start" if new_window and self.machine == "Windows" else ""
|
|
204
|
-
# os.system(f"{window} {terminal} {shell} {shell_script}")
|
|
205
|
-
|
|
206
|
-
# @staticmethod
|
|
207
|
-
# def run_as_admin(file: PLike, params: Any, wait: bool = False):
|
|
208
|
-
# proce_info = install_n_import(library="win32com", package="pywin32", fromlist=["shell.shell.ShellExecuteEx"]).shell.shell.ShellExecuteEx(lpVerb='runas', lpFile=file, lpParameters=params)
|
|
209
|
-
# # TODO update PATH for this to take effect immediately.
|
|
210
|
-
# if wait: time.sleep(1)
|
|
211
|
-
# return proce_info
|
|
@@ -47,7 +47,7 @@ machineconfig/cluster/templates/cli_trogon.py,sha256=PFWGy8SFYIhT9r3ZV4oIEYfImsQ
|
|
|
47
47
|
machineconfig/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
48
48
|
machineconfig/jobs/installer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
49
49
|
machineconfig/jobs/installer/check_installations.py,sha256=hkHmmT7Bx3_QWRn2v8dCKOzAapFzqHRzbe-Q08GLnKE,10743
|
|
50
|
-
machineconfig/jobs/installer/installer_data.json,sha256=
|
|
50
|
+
machineconfig/jobs/installer/installer_data.json,sha256=h0k4xeqURIj1dl5BrZxAdAi-3ywbDHPxyDkWFPuZK-k,76471
|
|
51
51
|
machineconfig/jobs/installer/package_groups.py,sha256=i4z83F_rk7BVsrwFhz5Vn4SLF0IHxyQBFSxpAaZBl8M,5270
|
|
52
52
|
machineconfig/jobs/installer/custom/gh.py,sha256=gn7TUSrsLx7uqFqj1Z-iYglS0EYBSgtJ9jWHxaJIfXM,4119
|
|
53
53
|
machineconfig/jobs/installer/custom/hx.py,sha256=YQClQXqWtGvon8BLFGf1Fp20JPkHgZeEZ6ebmCJQQfI,5838
|
|
@@ -97,7 +97,7 @@ machineconfig/profile/bash_shell_profiles.md,sha256=mio0xkMTwO-F3fikWIfgcdQaPCmQ
|
|
|
97
97
|
machineconfig/profile/create_helper.py,sha256=_iNeuwmcEGTx6sf_f40JKHfOCuJRZQRpyE8Fo_3Q6bI,1519
|
|
98
98
|
machineconfig/profile/create_links.py,sha256=K7T2bq08GZP9fo2NzCOE0pojAgQDe0Ofe7fNfbQlQpw,14219
|
|
99
99
|
machineconfig/profile/create_links_export.py,sha256=6LW4ZzHhQaox6W-rAuw3_gENTVKmOXA8_JfVDA-Mfws,3294
|
|
100
|
-
machineconfig/profile/create_shell_profile.py,sha256=
|
|
100
|
+
machineconfig/profile/create_shell_profile.py,sha256=fib3YOj4QMV4dy7ysJtSzner1x-0nGtnGvnTKGyq578,10280
|
|
101
101
|
machineconfig/profile/mapper.toml,sha256=CGGKi4VbRo1-AuHU7w1g94NbAys0pxn6fI-2l-lUmY0,12469
|
|
102
102
|
machineconfig/profile/records/generic/shares.toml,sha256=FduDztfyQtZcr5bfx-RSKhEEweweQSWfVXkKWnx8hCY,143
|
|
103
103
|
machineconfig/profile/records/linux/apps_summary_report.csv,sha256=pw9djvaRUPalKDLn2sl3odcbD2_Zx3aEupsQ8UPfaaY,2738
|
|
@@ -122,15 +122,15 @@ machineconfig/scripts/linux/other/switch_ip,sha256=NQfeKMBSbFY3eP6M-BadD-TQo5qMP
|
|
|
122
122
|
machineconfig/scripts/python/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
123
123
|
machineconfig/scripts/python/agents.py,sha256=gGeeWCI0AN_DyDJ3G5KR9qSsXv8zkUd5dBRRWqz-dQE,10722
|
|
124
124
|
machineconfig/scripts/python/cloud.py,sha256=yAD6ciKiEtv2CH3g2NScDK5cpCZQi7Vu8yyeehw_cU8,1263
|
|
125
|
-
machineconfig/scripts/python/croshell.py,sha256=
|
|
125
|
+
machineconfig/scripts/python/croshell.py,sha256=alixA33il7ssklDY59vb_g31xF9JNe_DP1c89pCg4C4,8205
|
|
126
126
|
machineconfig/scripts/python/devops.py,sha256=Lv4d-UlyOREj4VTcu_pxswYo54Mawe3XGeKjreGQDYg,2222
|
|
127
127
|
machineconfig/scripts/python/devops_navigator.py,sha256=5Cm384D4S8_GsvMzTwr0C16D0ktf8_5Mk5bEJncwDO8,237
|
|
128
128
|
machineconfig/scripts/python/entry.py,sha256=liCf186Msa6R-EjcQ0I6K80Km7Wi8qckJB6rXIHeHU0,2488
|
|
129
129
|
machineconfig/scripts/python/fire_jobs.py,sha256=My7sFn1R2vh21uIHGfNppgX99WTEitCFgJ1MSasBUOQ,13597
|
|
130
|
-
machineconfig/scripts/python/ftpx.py,sha256=
|
|
130
|
+
machineconfig/scripts/python/ftpx.py,sha256=A13hL_tDYfcsaK9PkshK-0lrUS6KPhPCtwqWtLSo6IM,9764
|
|
131
131
|
machineconfig/scripts/python/interactive.py,sha256=zt3g6nGKR_Y5A57UnR4Y5-JpLzrpnCOSaqU1bnaikK0,11666
|
|
132
132
|
machineconfig/scripts/python/sessions.py,sha256=UERxO472EDtN7nKHEULbn6G3S5PJIpsDG9Gq3TlByqI,9823
|
|
133
|
-
machineconfig/scripts/python/utils.py,sha256=
|
|
133
|
+
machineconfig/scripts/python/utils.py,sha256=c9HsKG40i5ggwqKuS3O-LCScuFpmxMVKqWpsFHx2dJc,934
|
|
134
134
|
machineconfig/scripts/python/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
135
135
|
machineconfig/scripts/python/ai/generate_files.py,sha256=VfjKdwgF8O6E4oiRtfWNliibLmmwGe7f9ld6wpOsXTw,14498
|
|
136
136
|
machineconfig/scripts/python/ai/initai.py,sha256=9SZtWOcRuwk8ZU3wHOfPzjInERD79ZTYFY8tVACgza4,2260
|
|
@@ -163,7 +163,7 @@ machineconfig/scripts/python/ai/solutions/opencode/opencode.json,sha256=nahHKRw1
|
|
|
163
163
|
machineconfig/scripts/python/ai/solutions/opencode/opencode.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
164
164
|
machineconfig/scripts/python/env_manager/__init__.py,sha256=E4LAHbU1wo2dLjE36ntv8U7QNTe8TasujUAYK9SLvWk,6
|
|
165
165
|
machineconfig/scripts/python/env_manager/path_manager_backend.py,sha256=ZVGlGJALhg7zNABDdwXxL7MFbL2BXPebObipXSLGbic,1552
|
|
166
|
-
machineconfig/scripts/python/env_manager/path_manager_tui.py,sha256=
|
|
166
|
+
machineconfig/scripts/python/env_manager/path_manager_tui.py,sha256=QxAnIuoen-hmziRoimoZmiO6WxJpCqVTVr_7ny4cVao,6932
|
|
167
167
|
machineconfig/scripts/python/helpers_cloud/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
168
168
|
machineconfig/scripts/python/helpers_cloud/cloud_copy.py,sha256=OV1w3ajFVFs6FJytjIPOntYB_aW2ywGohKi73V4Dm2Y,8691
|
|
169
169
|
machineconfig/scripts/python/helpers_cloud/cloud_helpers.py,sha256=GA-bxXouUmknk9fyQAsPT-Xl3RG9-yBed71a2tu9Pig,4914
|
|
@@ -179,15 +179,15 @@ machineconfig/scripts/python/helpers_croshell/start_slidev.py,sha256=HfJReOusTPh
|
|
|
179
179
|
machineconfig/scripts/python/helpers_croshell/viewer.py,sha256=heQNjB9fwn3xxbPgMofhv1Lp6Vtkl76YjjexWWBM0pM,2041
|
|
180
180
|
machineconfig/scripts/python/helpers_croshell/viewer_template.py,sha256=ve3Q1-iKhCLc0VJijKvAeOYp2xaFOeIOC_XW956GWCc,3944
|
|
181
181
|
machineconfig/scripts/python/helpers_devops/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
182
|
-
machineconfig/scripts/python/helpers_devops/cli_config.py,sha256=
|
|
182
|
+
machineconfig/scripts/python/helpers_devops/cli_config.py,sha256=5d0kGMU0AfQExub8af781iX4TJSF3Eb9OdSVFg1lWpk,7218
|
|
183
183
|
machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py,sha256=rjTys4FNf9_feP9flWM7Zvq17dxWmetSiGaHPxp25nk,2737
|
|
184
184
|
machineconfig/scripts/python/helpers_devops/cli_data.py,sha256=79Xvx7YnbueruEnl69hrDg2AhVxf_zCUdlVcKfeMGyQ,1774
|
|
185
185
|
machineconfig/scripts/python/helpers_devops/cli_nw.py,sha256=B5Xa9pV5MdC4vPo3EmKaHvNMlThsY3c5F92YPE5j3rI,4176
|
|
186
186
|
machineconfig/scripts/python/helpers_devops/cli_repos.py,sha256=Xwkv1adqHZvTfRSPWiqSK3PZ1XADyx3llw_YkbxaKyE,12505
|
|
187
|
-
machineconfig/scripts/python/helpers_devops/cli_self.py,sha256=
|
|
187
|
+
machineconfig/scripts/python/helpers_devops/cli_self.py,sha256=0-R7YDIQS2cH2n9C7lShFoBRwbytQz3BCuHGQrus7FU,6225
|
|
188
188
|
machineconfig/scripts/python/helpers_devops/cli_share_server.py,sha256=q9pFJ6AxPuygMr3onMNOKEuuQHbVE_6Qoyo7xRT5FX0,4196
|
|
189
189
|
machineconfig/scripts/python/helpers_devops/cli_terminal.py,sha256=k_PzXaiGyE0vXr0Ii1XcJz2A7UvyPJrR31TRWt4RKRI,6019
|
|
190
|
-
machineconfig/scripts/python/helpers_devops/cli_utils.py,sha256=
|
|
190
|
+
machineconfig/scripts/python/helpers_devops/cli_utils.py,sha256=jN_GeZyy-9tAJoBoASsmn9_tI7ZgkgXp7Ijgi2x_ssw,6053
|
|
191
191
|
machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py,sha256=Dn8luB6QJzxKiiFSC-NMqiYddWZoca3A8eOjMYZDzTc,5598
|
|
192
192
|
machineconfig/scripts/python/helpers_devops/devops_status.py,sha256=PJVPhfhXq8der6Xd-_fjZfnizfM-RGfJApkRGhGBmNo,20525
|
|
193
193
|
machineconfig/scripts/python/helpers_devops/devops_update_repos.py,sha256=kSln8_-Wn7Qu0NaKdt-QTN_bBVyTIAWHH8xVYKK-vCM,10133
|
|
@@ -225,7 +225,7 @@ machineconfig/scripts/python/helpers_navigator/main_app.py,sha256=R1vOBMUKaiFHOg
|
|
|
225
225
|
machineconfig/scripts/python/helpers_navigator/search_bar.py,sha256=kDi8Jhxap8wdm7YpDBtfhwcPnSqDPFrV2LqbcSBWMT4,414
|
|
226
226
|
machineconfig/scripts/python/helpers_repos/action.py,sha256=9AxWy8mB9HFeV5t11-qD_l-KA5jkUmm0pXVKT1L6-Qk,14894
|
|
227
227
|
machineconfig/scripts/python/helpers_repos/clone.py,sha256=UULEG5xJuXlPGU0nqXH6U45jA9DOFqLw8B4iPytCwOQ,5471
|
|
228
|
-
machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py,sha256=
|
|
228
|
+
machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py,sha256=vkNFnvtWWb726oIje6Eg2uN34-mmxTmTLZZvrQLnhcs,10408
|
|
229
229
|
machineconfig/scripts/python/helpers_repos/count_lines.py,sha256=Q5c7b-DxvTlQmljoic7niTuiAVyFlwYvkVQ7uRJHiTo,16009
|
|
230
230
|
machineconfig/scripts/python/helpers_repos/count_lines_frontend.py,sha256=vSDtrF4829jziwp6WZmGt9G8MJ9jY4hfXqtf0vhkYSE,607
|
|
231
231
|
machineconfig/scripts/python/helpers_repos/entrypoint.py,sha256=WYEFGUJp9HWImlFjbs_hiFZrUqM_KEYm5VvSUjWd04I,2810
|
|
@@ -241,7 +241,7 @@ machineconfig/scripts/python/nw/add_ssh_key.py,sha256=9JLmWu8pE7PAL5VuCFd19iVEdC
|
|
|
241
241
|
machineconfig/scripts/python/nw/devops_add_identity.py,sha256=aPjcHbTLhxYwWYcandyAHdwuO15ZBu3fB82u6bI0tMQ,3773
|
|
242
242
|
machineconfig/scripts/python/nw/devops_add_ssh_key.py,sha256=CkIl85hZLtG9k7yXLSzqi88YrilHV4hIUWHAPBwxWjw,8922
|
|
243
243
|
machineconfig/scripts/python/nw/mount_drive,sha256=zemKofv7hOmRN_V3qK0q580GkfWw3VdikyVVQyiu8j8,3514
|
|
244
|
-
machineconfig/scripts/python/nw/mount_nfs,sha256=
|
|
244
|
+
machineconfig/scripts/python/nw/mount_nfs,sha256=SRTinu_1lRrUpn6G_HXcT_cWD99u5kMWZ4C2GGWbCvE,1855
|
|
245
245
|
machineconfig/scripts/python/nw/mount_nfs.py,sha256=lOMDY4RS7tx8gsCazVR5tNNwFbaRyO2PJlnwBCDQgCM,3573
|
|
246
246
|
machineconfig/scripts/python/nw/mount_nw_drive,sha256=BqjGBCbwe5ZAsZDO3L0zHhh_gJfZy1CYOcqXA4Y-WkQ,2262
|
|
247
247
|
machineconfig/scripts/python/nw/mount_nw_drive.py,sha256=iru6AtnTyvyuk6WxlK5R4lDkuliVpPV5_uBTVVhXtjQ,1550
|
|
@@ -258,7 +258,7 @@ machineconfig/scripts/windows/fzfrga.bat,sha256=rU_KBMO6ii2EZ0akMnmDk9vpuhKSUZqk
|
|
|
258
258
|
machineconfig/scripts/windows/mounts/mount_nfs.ps1,sha256=XrAdzpxE6a4OccSmWJ7YWHJTnsZK8uXnFE5j9GOPA20,2026
|
|
259
259
|
machineconfig/scripts/windows/mounts/mount_nw.ps1,sha256=puxcfZc3ZCJerm8pj8OZGVoTYkhzp-h7oV-MrksSqIE,454
|
|
260
260
|
machineconfig/scripts/windows/mounts/mount_smb.ps1,sha256=PzYWpIO9BpwXjdWlUQL9pnMRnOGNSkxfh4bHukJFme8,69
|
|
261
|
-
machineconfig/scripts/windows/mounts/mount_ssh.ps1,sha256=
|
|
261
|
+
machineconfig/scripts/windows/mounts/mount_ssh.ps1,sha256=UlfzENsubfyBBHfkbuEsL9IkmJgzbb4Przc8GoTCcIg,322
|
|
262
262
|
machineconfig/scripts/windows/mounts/share_cloud.cmd,sha256=exD7JCdxw2LqVjw2MKCYHbVZlEqmelXtwnATng-dhJ4,1028
|
|
263
263
|
machineconfig/scripts/windows/mounts/share_smb.ps1,sha256=U7x8ULYSjbgzTtiHNSKQuTaZ_apilDvkGV5Xm5hXk5M,384
|
|
264
264
|
machineconfig/scripts/windows/mounts/unlock_bitlocker.ps1,sha256=Wv-SLscdckV-1mG3p82VXKPY9zW3hgkRmcLUXIZ1daE,253
|
|
@@ -337,7 +337,7 @@ machineconfig/settings/shells/ipy/profiles/default/startup/playext.py,sha256=OJ3
|
|
|
337
337
|
machineconfig/settings/shells/kitty/kitty.conf,sha256=lDdx-dUX3jbKGb3BkS2f2TOpmgGiS-CI-_-lFvhD5A4,52870
|
|
338
338
|
machineconfig/settings/shells/nushell/config.nu,sha256=xtko80MPteDXuOJmwJHNFhXmfHT6fIBfmTgsF29GiEc,748
|
|
339
339
|
machineconfig/settings/shells/nushell/env.nu,sha256=4VmaXb-qP6qnMD5TPzkXMLFNlB5QC4l9HEzCvXZE2GQ,315
|
|
340
|
-
machineconfig/settings/shells/pwsh/init.ps1,sha256=
|
|
340
|
+
machineconfig/settings/shells/pwsh/init.ps1,sha256=g1C4bgy2ZVTGD4fhBYMmSI526QBU5cqKYEO0hK7iWj0,1970
|
|
341
341
|
machineconfig/settings/shells/pwsh/profile.ps1,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
342
342
|
machineconfig/settings/shells/starship/starship.toml,sha256=5rQTY7ZpKnrnhgu2Y9OJKUYMz5lPLIftO1p1VRuVZwQ,1150
|
|
343
343
|
machineconfig/settings/shells/vtm/settings.xml,sha256=5TNXd-i0eUGo2w3tuhY9aOkwoJdqih8_HO_U6uL2Dts,18262
|
|
@@ -375,7 +375,7 @@ machineconfig/setup_linux/others/mint_keyboard_shortcuts.sh,sha256=F5dbg0n9RHsKG
|
|
|
375
375
|
machineconfig/setup_linux/ssh/openssh_all.sh,sha256=3dg6HEUFbHQOzLfSAtzK_D_GB8rGCCp_aBnxNdnidVc,824
|
|
376
376
|
machineconfig/setup_linux/ssh/openssh_wsl.sh,sha256=1eeRGrloVB34K5z8yWVUMG5b9pV-WBfHgV9jqXiYgCQ,1398
|
|
377
377
|
machineconfig/setup_linux/web_shortcuts/android.sh,sha256=gzep6bBhK7FCBvGcXK0fdJCtkSfBOftt0aFyDZq_eMs,68
|
|
378
|
-
machineconfig/setup_linux/web_shortcuts/interactive.sh,sha256=
|
|
378
|
+
machineconfig/setup_linux/web_shortcuts/interactive.sh,sha256=IK7v55VGTGpBt5imTtFkqwuRVbpWGenigVaczX2vefo,464
|
|
379
379
|
machineconfig/setup_mac/__init__.py,sha256=Q1waupi5vCBroLqc8Rtnw69_7jLnm2Cs7_zH_GSZgMs,616
|
|
380
380
|
machineconfig/setup_mac/apps.sh,sha256=R0N6fBwLCzwy4qAormyMerXXXrHazibSkY6NrNOpTQU,2772
|
|
381
381
|
machineconfig/setup_mac/uv.sh,sha256=CSN8oCBKS-LK1vJJqYOhAMcrouTf4Q_F3cpplc_ddMA,1157
|
|
@@ -389,7 +389,7 @@ machineconfig/setup_windows/others/power_options.ps1,sha256=c7Hn94jBD5GWF29CxMhm
|
|
|
389
389
|
machineconfig/setup_windows/ssh/add-sshkey.ps1,sha256=qfPdqCpd9KP3VhH4ifsUm1Xvec7c0QVl4Wt8JIAm9HQ,1653
|
|
390
390
|
machineconfig/setup_windows/ssh/add_identity.ps1,sha256=b8ZXpmNUSw3IMYvqSY7ClpdWPG39FS7MefoWnRhWN2U,506
|
|
391
391
|
machineconfig/setup_windows/ssh/openssh-server.ps1,sha256=OMlYQdvuJQNxF5EILLPizB6BZAT3jAmDsv1WcVVxpFQ,2529
|
|
392
|
-
machineconfig/setup_windows/web_shortcuts/interactive.ps1,sha256=
|
|
392
|
+
machineconfig/setup_windows/web_shortcuts/interactive.ps1,sha256=Q-LfSjqEpI5ODQceycTA1b-OsMw1bXDBD26YBnIA4Cs,581
|
|
393
393
|
machineconfig/setup_windows/wt_and_pwsh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
394
394
|
machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py,sha256=ogxJnwpdcpH7N6dFJu95UCNoGYirZKQho_3X0F_hmXs,6791
|
|
395
395
|
machineconfig/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -407,8 +407,8 @@ machineconfig/utils/procs.py,sha256=YPA_vEYQGwPd_o_Lc6nOTBo5BrB1tSs8PJ42XiGpenM,
|
|
|
407
407
|
machineconfig/utils/scheduler.py,sha256=44CASABJg3epccxhAwv2CX7TVgZh6zVy3K4vqHKTuf4,14228
|
|
408
408
|
machineconfig/utils/scheduling.py,sha256=6x5zLA7sY5gohrEtN6zGrXIqNFasMoyBfwLcOjrjiME,11109
|
|
409
409
|
machineconfig/utils/source_of_truth.py,sha256=ZAnCRltiM07ig--P6g9_6nEAvNFC4X4ERFTVcvpIYsE,764
|
|
410
|
-
machineconfig/utils/ssh.py,sha256=
|
|
411
|
-
machineconfig/utils/terminal.py,sha256=
|
|
410
|
+
machineconfig/utils/ssh.py,sha256=lTvhFr9A2yNe6MbtcBMSl_d3wjeIfrkMUrREgMcZ7zk,35791
|
|
411
|
+
machineconfig/utils/terminal.py,sha256=VDgsjTjBmMGgZN0YIc0pJ8YksLDrBtiXON1EThy7_is,4264
|
|
412
412
|
machineconfig/utils/tst.py,sha256=6u1GI49NdcpxH2BYGAusNfY5q9G_ytCGVzFM5b6HYpM,674
|
|
413
413
|
machineconfig/utils/upgrade_packages.py,sha256=mSFyKvB3JhHte_x1dtmEgrJZCAXgTUQoaJUSx1OXQ3Y,4145
|
|
414
414
|
machineconfig/utils/ve.py,sha256=L-6PBXnQGXThiwWgheJMQoisAZOZA6SVCbGw2J-GFnI,2414
|
|
@@ -436,8 +436,8 @@ machineconfig/utils/schemas/installer/installer_types.py,sha256=QClRY61QaduBPJoS
|
|
|
436
436
|
machineconfig/utils/schemas/layouts/layout_types.py,sha256=TcqlZdGVoH8htG5fHn1KWXhRdPueAcoyApppZsPAPto,2020
|
|
437
437
|
machineconfig/utils/schemas/repos/repos_types.py,sha256=ECVr-3IVIo8yjmYmVXX2mnDDN1SLSwvQIhx4KDDQHBQ,405
|
|
438
438
|
machineconfig/utils/ssh_utils/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
439
|
-
machineconfig-6.
|
|
440
|
-
machineconfig-6.
|
|
441
|
-
machineconfig-6.
|
|
442
|
-
machineconfig-6.
|
|
443
|
-
machineconfig-6.
|
|
439
|
+
machineconfig-6.62.dist-info/METADATA,sha256=VjucUVQDh7RyqFcRHJooUz1f528jVpPQ6_ilmkmPrVo,2928
|
|
440
|
+
machineconfig-6.62.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
441
|
+
machineconfig-6.62.dist-info/entry_points.txt,sha256=NTW7hbUlpt5Vx9DdQrONLkYMCuBXpvYh1dt0AtlGxeI,466
|
|
442
|
+
machineconfig-6.62.dist-info/top_level.txt,sha256=porRtB8qms8fOIUJgK-tO83_FeH6Bpe12oUVC670teA,14
|
|
443
|
+
machineconfig-6.62.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|