portacode 1.4.13.dev3__py3-none-any.whl → 1.4.13.dev5__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.
- portacode/_version.py +2 -2
- portacode/connection/handlers/proxmox_infra.py +55 -20
- {portacode-1.4.13.dev3.dist-info → portacode-1.4.13.dev5.dist-info}/METADATA +1 -1
- {portacode-1.4.13.dev3.dist-info → portacode-1.4.13.dev5.dist-info}/RECORD +8 -8
- {portacode-1.4.13.dev3.dist-info → portacode-1.4.13.dev5.dist-info}/WHEEL +0 -0
- {portacode-1.4.13.dev3.dist-info → portacode-1.4.13.dev5.dist-info}/entry_points.txt +0 -0
- {portacode-1.4.13.dev3.dist-info → portacode-1.4.13.dev5.dist-info}/licenses/LICENSE +0 -0
- {portacode-1.4.13.dev3.dist-info → portacode-1.4.13.dev5.dist-info}/top_level.txt +0 -0
portacode/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '1.4.13.
|
|
32
|
-
__version_tuple__ = version_tuple = (1, 4, 13, '
|
|
31
|
+
__version__ = version = '1.4.13.dev5'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 4, 13, 'dev5')
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -3,20 +3,21 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
|
-
import base64
|
|
7
6
|
import json
|
|
8
7
|
import logging
|
|
9
8
|
import os
|
|
10
9
|
import secrets
|
|
10
|
+
import shlex
|
|
11
11
|
import shutil
|
|
12
12
|
import stat
|
|
13
13
|
import subprocess
|
|
14
14
|
import sys
|
|
15
|
+
import tempfile
|
|
15
16
|
import time
|
|
16
17
|
import threading
|
|
17
18
|
from datetime import datetime
|
|
18
19
|
from pathlib import Path
|
|
19
|
-
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple
|
|
20
|
+
from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple
|
|
20
21
|
|
|
21
22
|
import platformdirs
|
|
22
23
|
|
|
@@ -688,34 +689,68 @@ def _run_pct_check(vmid: int, cmd: str) -> Dict[str, Any]:
|
|
|
688
689
|
return res
|
|
689
690
|
|
|
690
691
|
|
|
692
|
+
def _run_pct_exec(vmid: int, command: Sequence[str]) -> subprocess.CompletedProcess[str]:
|
|
693
|
+
return _call_subprocess(["pct", "exec", str(vmid), "--", *command])
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
def _run_pct_exec_check(vmid: int, command: Sequence[str]) -> subprocess.CompletedProcess[str]:
|
|
697
|
+
res = _run_pct_exec(vmid, command)
|
|
698
|
+
if res.returncode != 0:
|
|
699
|
+
raise RuntimeError(res.stderr or res.stdout or f"pct exec {' '.join(command)} failed")
|
|
700
|
+
return res
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
def _run_pct_push(vmid: int, src: str, dest: str) -> subprocess.CompletedProcess[str]:
|
|
704
|
+
return _call_subprocess(["pct", "push", str(vmid), src, dest])
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
def _push_bytes_to_container(
|
|
708
|
+
vmid: int, user: str, path: str, data: bytes, mode: int = 0o600
|
|
709
|
+
) -> None:
|
|
710
|
+
logger.debug("Preparing to push %d bytes to container vmid=%s path=%s for user=%s", len(data), vmid, path, user)
|
|
711
|
+
tmp_path: Optional[str] = None
|
|
712
|
+
try:
|
|
713
|
+
parent = Path(path).parent
|
|
714
|
+
parent_str = parent.as_posix()
|
|
715
|
+
if parent_str not in {"", ".", "/"}:
|
|
716
|
+
_run_pct_exec_check(vmid, ["mkdir", "-p", parent_str])
|
|
717
|
+
|
|
718
|
+
with tempfile.NamedTemporaryFile(delete=False) as tmp:
|
|
719
|
+
tmp.write(data)
|
|
720
|
+
tmp.flush()
|
|
721
|
+
os.fsync(tmp.fileno())
|
|
722
|
+
tmp_path = tmp.name
|
|
723
|
+
|
|
724
|
+
push_res = _run_pct_push(vmid, tmp_path, path)
|
|
725
|
+
if push_res.returncode != 0:
|
|
726
|
+
raise RuntimeError(push_res.stderr or push_res.stdout or f"pct push returned {push_res.returncode}")
|
|
727
|
+
|
|
728
|
+
_run_pct_exec_check(vmid, ["chown", f"{user}:{user}", path])
|
|
729
|
+
_run_pct_exec_check(vmid, ["chmod", format(mode, "o"), path])
|
|
730
|
+
logger.debug("Successfully pushed %d bytes to vmid=%s path=%s", len(data), vmid, path)
|
|
731
|
+
except Exception as exc:
|
|
732
|
+
logger.error("Failed to write to container vmid=%s path=%s for user=%s: %s", vmid, path, user, exc)
|
|
733
|
+
raise
|
|
734
|
+
finally:
|
|
735
|
+
if tmp_path:
|
|
736
|
+
try:
|
|
737
|
+
os.remove(tmp_path)
|
|
738
|
+
except OSError as cleanup_exc:
|
|
739
|
+
logger.warning("Failed to remove temporary file %s: %s", tmp_path, cleanup_exc)
|
|
740
|
+
|
|
741
|
+
|
|
691
742
|
def _resolve_portacode_key_dir(vmid: int, user: str) -> str:
|
|
692
743
|
data_dir_cmd = f"su - {user} -c 'echo -n ${{XDG_DATA_HOME:-$HOME/.local/share}}'"
|
|
693
744
|
data_home = _run_pct_check(vmid, data_dir_cmd)["stdout"].strip()
|
|
694
745
|
return f"{data_home}/portacode/keys"
|
|
695
746
|
|
|
696
747
|
|
|
697
|
-
def _write_bytes_as_user(vmid: int, user: str, path: str, data: bytes, mode: int = 0o600) -> None:
|
|
698
|
-
encoded = base64.b64encode(data).decode()
|
|
699
|
-
path_literal = json.dumps(path)
|
|
700
|
-
script = (
|
|
701
|
-
f"su - {user} -c 'python3 - <<\"PY\"\n"
|
|
702
|
-
"import base64\n"
|
|
703
|
-
"from pathlib import Path\n"
|
|
704
|
-
f"path = Path({path_literal})\n"
|
|
705
|
-
"path.parent.mkdir(parents=True, exist_ok=True)\n"
|
|
706
|
-
f"path.write_bytes(base64.b64decode(\"{encoded}\"))\n"
|
|
707
|
-
f"path.chmod({mode})\n"
|
|
708
|
-
"PY'"
|
|
709
|
-
)
|
|
710
|
-
_run_pct_check(vmid, script)
|
|
711
|
-
|
|
712
|
-
|
|
713
748
|
def _deploy_device_keypair(vmid: int, user: str, private_key: str, public_key: str) -> None:
|
|
714
749
|
key_dir = _resolve_portacode_key_dir(vmid, user)
|
|
715
750
|
priv_path = f"{key_dir}/id_portacode"
|
|
716
751
|
pub_path = f"{key_dir}/id_portacode.pub"
|
|
717
|
-
|
|
718
|
-
|
|
752
|
+
_push_bytes_to_container(vmid, user, priv_path, private_key.encode(), mode=0o600)
|
|
753
|
+
_push_bytes_to_container(vmid, user, pub_path, public_key.encode(), mode=0o644)
|
|
719
754
|
|
|
720
755
|
|
|
721
756
|
def _portacode_connect_and_read_key(vmid: int, user: str, timeout_s: int = 10) -> Dict[str, Any]:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
portacode/README.md,sha256=4dKtpvR8LNgZPVz37GmkQCMWIr_u25Ao63iW56s7Ke4,775
|
|
2
2
|
portacode/__init__.py,sha256=oB3sV1wXr-um-RXio73UG8E5Xx6cF2ZVJveqjNmC-vQ,1086
|
|
3
3
|
portacode/__main__.py,sha256=jmHTGC1hzmo9iKJLv-SSYe9BSIbPPZ2IOpecI03PlTs,296
|
|
4
|
-
portacode/_version.py,sha256
|
|
4
|
+
portacode/_version.py,sha256=-8qHEfgIuA1gX0IiXHXHG1Zfu4eNnZLDSsV3Lsp8upE,719
|
|
5
5
|
portacode/cli.py,sha256=mGLKoZ-T2FBF7IA9wUq0zyG0X9__-A1ao7gajjcVRH8,21828
|
|
6
6
|
portacode/data.py,sha256=5-s291bv8J354myaHm1Y7CQZTZyRzMU3TGe5U4hb-FA,1591
|
|
7
7
|
portacode/keypair.py,sha256=0OO4vHDcF1XMxCDqce61xFTlFwlTcmqe5HyGsXFEt7s,5838
|
|
@@ -22,7 +22,7 @@ portacode/connection/handlers/diff_handlers.py,sha256=iYTIRCcpEQ03vIPKZCsMTE5aZb
|
|
|
22
22
|
portacode/connection/handlers/file_handlers.py,sha256=nAJH8nXnX07xxD28ngLpgIUzcTuRwZBNpEGEKdRqohw,39507
|
|
23
23
|
portacode/connection/handlers/project_aware_file_handlers.py,sha256=AqgMnDqX2893T2NsrvUSCwjN5VKj4Pb2TN0S_SuboOE,9803
|
|
24
24
|
portacode/connection/handlers/project_state_handlers.py,sha256=v6ZefGW9i7n1aZLq2jOGumJIjYb6aHlPI4m1jkYewm8,1686
|
|
25
|
-
portacode/connection/handlers/proxmox_infra.py,sha256=
|
|
25
|
+
portacode/connection/handlers/proxmox_infra.py,sha256=8-PTQqk-9abTY9DqWzUtabWDuMYpLNqw678vhjAQom4,60514
|
|
26
26
|
portacode/connection/handlers/registry.py,sha256=qXGE60sYEWg6ZtVQzFcZ5YI2XWR6lMgw4hAL9x5qR1I,6181
|
|
27
27
|
portacode/connection/handlers/session.py,sha256=uNGfiO_1B9-_yjJKkpvmbiJhIl6b-UXlT86UTfd6WYE,42219
|
|
28
28
|
portacode/connection/handlers/system_handlers.py,sha256=AKh7IbwptlLYrbSw5f-DHigvlaKHsg9lDP-lkAUm8cE,10755
|
|
@@ -65,7 +65,7 @@ portacode/utils/__init__.py,sha256=NgBlWTuNJESfIYJzP_3adI1yJQJR0XJLRpSdVNaBAN0,3
|
|
|
65
65
|
portacode/utils/diff_apply.py,sha256=4Oi7ft3VUCKmiUE4VM-OeqO7Gk6H7PF3WnN4WHXtjxI,15157
|
|
66
66
|
portacode/utils/diff_renderer.py,sha256=S76StnQ2DLfsz4Gg0m07UwPfRp8270PuzbNaQq-rmYk,13850
|
|
67
67
|
portacode/utils/ntp_clock.py,sha256=VqCnWCTehCufE43W23oB-WUdAZGeCcLxkmIOPwInYHc,2499
|
|
68
|
-
portacode-1.4.13.
|
|
68
|
+
portacode-1.4.13.dev5.dist-info/licenses/LICENSE,sha256=2FGbCnUDgRYuQTkB1O1dUUpu5CVAjK1j4_p6ack9Z54,1066
|
|
69
69
|
test_modules/README.md,sha256=Do_agkm9WhSzueXjRAkV_xEj6Emy5zB3N3VKY5Roce8,9274
|
|
70
70
|
test_modules/__init__.py,sha256=1LcbHodIHsB0g-g4NGjSn6AMuCoGbymvXPYLOb6Z7F0,53
|
|
71
71
|
test_modules/test_device_online.py,sha256=QtYq0Dq9vME8Gp2O4fGSheqVf8LUtpsSKosXXk56gGM,1654
|
|
@@ -91,8 +91,8 @@ testing_framework/core/playwright_manager.py,sha256=Tw46qwxIhOFkS48C2IWIQHHNpEe-
|
|
|
91
91
|
testing_framework/core/runner.py,sha256=j2QwNJmAxVBmJvcbVS7DgPJUKPNzqfLmt_4NNdaKmZU,19297
|
|
92
92
|
testing_framework/core/shared_cli_manager.py,sha256=BESSNtyQb7BOlaOvZmm04T8Uezjms4KCBs2MzTxvzYQ,8790
|
|
93
93
|
testing_framework/core/test_discovery.py,sha256=2FZ9fJ8Dp5dloA-fkgXoJ_gCMC_nYPBnA3Hs2xlagzM,4928
|
|
94
|
-
portacode-1.4.13.
|
|
95
|
-
portacode-1.4.13.
|
|
96
|
-
portacode-1.4.13.
|
|
97
|
-
portacode-1.4.13.
|
|
98
|
-
portacode-1.4.13.
|
|
94
|
+
portacode-1.4.13.dev5.dist-info/METADATA,sha256=2_UghpIjr0yiaPZRhlEMhiCy2Ii4hcA1JQl0jiVExy8,13051
|
|
95
|
+
portacode-1.4.13.dev5.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
|
|
96
|
+
portacode-1.4.13.dev5.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
|
|
97
|
+
portacode-1.4.13.dev5.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
|
|
98
|
+
portacode-1.4.13.dev5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|