portacode 1.4.13.dev3__py3-none-any.whl → 1.4.13.dev4__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 +50 -20
- {portacode-1.4.13.dev3.dist-info → portacode-1.4.13.dev4.dist-info}/METADATA +1 -1
- {portacode-1.4.13.dev3.dist-info → portacode-1.4.13.dev4.dist-info}/RECORD +8 -8
- {portacode-1.4.13.dev3.dist-info → portacode-1.4.13.dev4.dist-info}/WHEEL +0 -0
- {portacode-1.4.13.dev3.dist-info → portacode-1.4.13.dev4.dist-info}/entry_points.txt +0 -0
- {portacode-1.4.13.dev3.dist-info → portacode-1.4.13.dev4.dist-info}/licenses/LICENSE +0 -0
- {portacode-1.4.13.dev3.dist-info → portacode-1.4.13.dev4.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.dev4'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 4, 13, 'dev4')
|
|
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,63 @@ 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
|
+
with tempfile.NamedTemporaryFile(delete=False) as tmp:
|
|
714
|
+
tmp.write(data)
|
|
715
|
+
tmp.flush()
|
|
716
|
+
os.fsync(tmp.fileno())
|
|
717
|
+
tmp_path = tmp.name
|
|
718
|
+
|
|
719
|
+
push_res = _run_pct_push(vmid, tmp_path, path)
|
|
720
|
+
if push_res.returncode != 0:
|
|
721
|
+
raise RuntimeError(push_res.stderr or push_res.stdout or f"pct push returned {push_res.returncode}")
|
|
722
|
+
|
|
723
|
+
_run_pct_exec_check(vmid, ["chown", f"{user}:{user}", path])
|
|
724
|
+
_run_pct_exec_check(vmid, ["chmod", format(mode, "o"), path])
|
|
725
|
+
logger.debug("Successfully pushed %d bytes to vmid=%s path=%s", len(data), vmid, path)
|
|
726
|
+
except Exception as exc:
|
|
727
|
+
logger.error("Failed to write to container vmid=%s path=%s for user=%s: %s", vmid, path, user, exc)
|
|
728
|
+
raise
|
|
729
|
+
finally:
|
|
730
|
+
if tmp_path:
|
|
731
|
+
try:
|
|
732
|
+
os.remove(tmp_path)
|
|
733
|
+
except OSError as cleanup_exc:
|
|
734
|
+
logger.warning("Failed to remove temporary file %s: %s", tmp_path, cleanup_exc)
|
|
735
|
+
|
|
736
|
+
|
|
691
737
|
def _resolve_portacode_key_dir(vmid: int, user: str) -> str:
|
|
692
738
|
data_dir_cmd = f"su - {user} -c 'echo -n ${{XDG_DATA_HOME:-$HOME/.local/share}}'"
|
|
693
739
|
data_home = _run_pct_check(vmid, data_dir_cmd)["stdout"].strip()
|
|
694
740
|
return f"{data_home}/portacode/keys"
|
|
695
741
|
|
|
696
742
|
|
|
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
743
|
def _deploy_device_keypair(vmid: int, user: str, private_key: str, public_key: str) -> None:
|
|
714
744
|
key_dir = _resolve_portacode_key_dir(vmid, user)
|
|
715
745
|
priv_path = f"{key_dir}/id_portacode"
|
|
716
746
|
pub_path = f"{key_dir}/id_portacode.pub"
|
|
717
|
-
|
|
718
|
-
|
|
747
|
+
_push_bytes_to_container(vmid, user, priv_path, private_key.encode(), mode=0o600)
|
|
748
|
+
_push_bytes_to_container(vmid, user, pub_path, public_key.encode(), mode=0o644)
|
|
719
749
|
|
|
720
750
|
|
|
721
751
|
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=Fs9qvieZ__T0NcgTq_XxK_eFMBlTmdEvgXqq_uu2QV8,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=1woStijF43ceynNZtt1jEVzb_AA9_UqltrU8cqsUEGw,60327
|
|
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.dev4.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.dev4.dist-info/METADATA,sha256=JaS2exWbayOGy7ZrJu6Dzm6pJv3KhUWt7c6HkZAQ94E,13051
|
|
95
|
+
portacode-1.4.13.dev4.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
|
|
96
|
+
portacode-1.4.13.dev4.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
|
|
97
|
+
portacode-1.4.13.dev4.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
|
|
98
|
+
portacode-1.4.13.dev4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|