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.

@@ -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() -> PathExtended:
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 = PathExtended(result.stdout.strip())
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
- fire_line = f"uv run --with visidata,pyarrow vd {str(file_obj)}"
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" """
@@ -2,7 +2,7 @@
2
2
  # /// script
3
3
  # requires-python = ">=3.13"
4
4
  # dependencies = [
5
- # "machineconfig>=6.59",
5
+ # "machineconfig>=6.61",
6
6
  # "textual",
7
7
  # "pyperclip",
8
8
  # ]
@@ -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, target_path=resolved_target, compress_with_zip=zipFirst, recursive=recursive, overwrite_existing=False)
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.59")
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.59" """)
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.59" """)
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.59,textual" """
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
@@ -80,7 +80,7 @@ git pull originEnc master
80
80
  uv_project_dir = f"""{str(Path.home().joinpath("code/machineconfig"))}"""
81
81
  uv_with = None
82
82
  else:
83
- uv_with = ["machineconfig>=6.59"]
83
+ uv_with = ["machineconfig>=6.61"]
84
84
  uv_project_dir = None
85
85
 
86
86
  import tempfile
@@ -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.59" python -m machineconfig.scripts.python.mount_nfs
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.59" python -m machineconfig.scripts.python.mount_ssh
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 s { sessions @args }
37
+ function ss { sessions @args }
38
38
  function ff { ftpx @args }
39
39
  function f { fire @args }
40
- function r { croshell @args }
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.59" mcfg "$@"
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 s="mcfg sessions"
9
+ alias ss="mcfg sessions"
10
10
  alias ff="mcfg ftpx"
11
11
  alias f="mcfg fire"
12
- alias r="mcfg croshell"
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.59" mcfg $args
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 s { mcfg sessions @args }
10
+ function ss { mcfg sessions @args }
11
11
  function ff { mcfg ftpx @args }
12
12
  function f { mcfg fire @args }
13
- function r { mcfg croshell @args }
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."
@@ -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, MACHINE
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.59"
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
- self._local_distro: Optional[str] = None
115
- self._remote_distro: Optional[str] = None
116
- self._remote_machine: Optional[MACHINE] = None
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.get_remote_machine() == "Windows" else "sudo reboot", verbose_output=True, description="", strict_stderr=False, strict_return_code=False)
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=Path("~/.ssh/id_rsa.pub"), target_path=None, compress_with_zip=False, recursive=False, overwrite_existing=False)
156
- if self.get_remote_machine() != "Windows":
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.get_remote_machine()}][{self.get_remote_distro()}]" if add_machine else "")
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()}@{self.platform.node()}" + (f" [{self.platform.system()}][{self.get_local_distro()}]" if add_machine else "")
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.platform.node()} Command: {command}""")
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, target_path=None, compress_with_zip=False, recursive=False, overwrite_existing=False)
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
- from machineconfig.utils.meta import lambda_to_python_script
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 _create_remote_target_dir(self, target_path: Union[str, Path], overwrite_existing: bool) -> str:
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(target_dir_path: str, overwrite: bool, json_output_path: str) -> str:
199
+ def create_target_dir(target_rel2home: str, overwrite: bool) -> None:
224
200
  from pathlib import Path
225
201
  import shutil
226
- import json
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
- result_path_posix = directory_path.as_posix()
235
- json_result_path = Path(json_output_path)
236
- json_result_path.parent.mkdir(parents=True, exist_ok=True)
237
- json_result_path.write_text(json.dumps(result_path_posix, indent=2), encoding="utf-8")
238
- print(json_result_path.as_posix())
239
- return result_path_posix
240
- from machineconfig.utils.meta import lambda_to_python_script
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: Union[str, Path], target_path: Optional[Union[str, Path]], compress_with_zip: bool, recursive: bool, overwrite_existing: bool) -> 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
- raise RuntimeError(f"SSH Error: source `{source_obj}` does not exist!")
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
- remote_root = self._create_remote_target_dir(target_path=target_path, overwrite_existing=overwrite_existing)
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(remote_root).joinpath(file_path.relative_to(source_obj))
290
- self.copy_from_here(source_path=file_path, target_path=remote_file_target, compress_with_zip=False, recursive=False, overwrite_existing=overwrite_existing)
291
- return Path(remote_root)
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 str(target_path).endswith(".zip"):
302
- target_path = Path(str(target_path) + ".zip")
303
- remotepath_str = self._create_remote_target_dir(target_path=target_path, overwrite_existing=overwrite_existing)
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=remotepath.as_posix(), callback=pbar.view_bar) # type: ignore
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
- from machineconfig.utils.meta import lambda_to_python_script
329
- command = lambda_to_python_script(lmb=lambda: unzip_archive(zip_file_path=remotepath.as_posix(), overwrite_flag=overwrite_existing), in_global=True)
330
- _resp = self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None, description=f"UNZIPPING {remotepath.as_posix()}", verbose_output=False, strict_stderr=True, strict_return_code=True)
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 source_obj
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
- from machineconfig.utils.accessories import randstr
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
- from machineconfig.utils.meta import lambda_to_python_script
381
- from machineconfig.utils.accessories import randstr
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
- from machineconfig.utils.accessories import randstr
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
- from machineconfig.utils.meta import lambda_to_python_script
430
- from machineconfig.utils.accessories import randstr
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
- from machineconfig.utils.accessories import randstr
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
- from machineconfig.utils.meta import lambda_to_python_script
468
- from machineconfig.utils.accessories import randstr
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
- from machineconfig.utils.accessories import randstr
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
- from machineconfig.utils.meta import lambda_to_python_script
520
- from machineconfig.utils.accessories import randstr
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
- from machineconfig.utils.accessories import randstr
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
- from machineconfig.utils.meta import lambda_to_python_script
559
- from machineconfig.utils.accessories import randstr
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
- from machineconfig.utils.accessories import randstr
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
- from machineconfig.utils.meta import lambda_to_python_script
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)
@@ -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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: machineconfig
3
- Version: 6.59
3
+ Version: 6.62
4
4
  Summary: Dotfiles management package
5
5
  Author-email: Alex Al-Saffar <programmer@usa.com>
6
6
  License: Apache 2.0
@@ -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=11COZT-w9Ol052HpXJsGf8FhMcTNr2JNsuClYQgJjpc,75992
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=QcUT4ah0x-8Dv-Si_hlGJWWN9SbwWGPhzmzKv9vDK8s,10296
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=I8564dNdu41Kmmz6uD1sGX4_x6VzE6M7oUmuEGRMh4A,8075
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=vm4QNJA0z1Vu-85wFliGNoDHMZZ-Yy8zQACL6x7Wo6U,9760
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=rlrTomPlvhzaMf2UWzVeyO_kTwNWFj1iASXIF2g9cx8,710
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=oYxch9_mEkLntmua2av8F9XO5p_KxMmrJWfOpt1kyyQ,6932
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=4GDaSuOJcgfo4UXOp-QED3K8QCHFwEBMzfZpWL0lYBg,7218
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=VEZyXe3jffn_OHRS-Qj2uH1JnWKyq6FrLbA9xfks2hk,6225
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=sCYKR6bXzr6DgVnQrCa_pjKdc7tOOY3T8h1A41UURBU,5066
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=NsySJZE0HPj8rN3NHhlzVNOI2JKx7vGbScCfzWDNvwE,10408
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=SLqmLb9Lc4oJnFxOq70jqXDIv3zKt1faVkxTy0W3nb0,1855
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=EuLh6wKLvKMxqbSbhj9n1BFmeSfyzTAodFV7Tmgju-w,322
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=N2sh3ByaQWIF6J7Pg0_pIqbIG9iy4wJiUSKhtfns4ao,1968
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=tEQ9uyDCjKOOk2ahRq238SnQYTzImuYnwmGW4z1EcLQ,462
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=_2VCNSMh9cLZYH_NJIrqHKBqq_dMfXCeNMXPWti1XsU,579
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=esu8ANmZqb_d_4wmidqa7tFwwzIDJrmJxIcMQJzFx1U,39390
411
- machineconfig/utils/terminal.py,sha256=IlmOByfQG-vjhaFFxxzU5rWzP5_qUzmalRfuey3PAmc,11801
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.59.dist-info/METADATA,sha256=ZxTwM0IHtGUGO5T2r37koBvac2qlpRoeqV1TsLIozw0,2928
440
- machineconfig-6.59.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
441
- machineconfig-6.59.dist-info/entry_points.txt,sha256=NTW7hbUlpt5Vx9DdQrONLkYMCuBXpvYh1dt0AtlGxeI,466
442
- machineconfig-6.59.dist-info/top_level.txt,sha256=porRtB8qms8fOIUJgK-tO83_FeH6Bpe12oUVC670teA,14
443
- machineconfig-6.59.dist-info/RECORD,,
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,,