portacode 1.4.13.dev2__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 +51 -20
- {portacode-1.4.13.dev2.dist-info → portacode-1.4.13.dev4.dist-info}/METADATA +1 -1
- {portacode-1.4.13.dev2.dist-info → portacode-1.4.13.dev4.dist-info}/RECORD +8 -8
- {portacode-1.4.13.dev2.dist-info → portacode-1.4.13.dev4.dist-info}/WHEEL +0 -0
- {portacode-1.4.13.dev2.dist-info → portacode-1.4.13.dev4.dist-info}/entry_points.txt +0 -0
- {portacode-1.4.13.dev2.dist-info → portacode-1.4.13.dev4.dist-info}/licenses/LICENSE +0 -0
- {portacode-1.4.13.dev2.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,19 +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
|
|
16
|
+
import time
|
|
15
17
|
import threading
|
|
16
18
|
from datetime import datetime
|
|
17
19
|
from pathlib import Path
|
|
18
|
-
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple
|
|
20
|
+
from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple
|
|
19
21
|
|
|
20
22
|
import platformdirs
|
|
21
23
|
|
|
@@ -687,34 +689,63 @@ def _run_pct_check(vmid: int, cmd: str) -> Dict[str, Any]:
|
|
|
687
689
|
return res
|
|
688
690
|
|
|
689
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
|
+
|
|
690
737
|
def _resolve_portacode_key_dir(vmid: int, user: str) -> str:
|
|
691
738
|
data_dir_cmd = f"su - {user} -c 'echo -n ${{XDG_DATA_HOME:-$HOME/.local/share}}'"
|
|
692
739
|
data_home = _run_pct_check(vmid, data_dir_cmd)["stdout"].strip()
|
|
693
740
|
return f"{data_home}/portacode/keys"
|
|
694
741
|
|
|
695
742
|
|
|
696
|
-
def _write_bytes_as_user(vmid: int, user: str, path: str, data: bytes, mode: int = 0o600) -> None:
|
|
697
|
-
encoded = base64.b64encode(data).decode()
|
|
698
|
-
path_literal = json.dumps(path)
|
|
699
|
-
script = (
|
|
700
|
-
f"su - {user} -c 'python3 - <<\"PY\"\n"
|
|
701
|
-
"import base64\n"
|
|
702
|
-
"from pathlib import Path\n"
|
|
703
|
-
f"path = Path({path_literal})\n"
|
|
704
|
-
"path.parent.mkdir(parents=True, exist_ok=True)\n"
|
|
705
|
-
f"path.write_bytes(base64.b64decode(\"{encoded}\"))\n"
|
|
706
|
-
f"path.chmod({mode})\n"
|
|
707
|
-
"PY'"
|
|
708
|
-
)
|
|
709
|
-
_run_pct_check(vmid, script)
|
|
710
|
-
|
|
711
|
-
|
|
712
743
|
def _deploy_device_keypair(vmid: int, user: str, private_key: str, public_key: str) -> None:
|
|
713
744
|
key_dir = _resolve_portacode_key_dir(vmid, user)
|
|
714
745
|
priv_path = f"{key_dir}/id_portacode"
|
|
715
746
|
pub_path = f"{key_dir}/id_portacode.pub"
|
|
716
|
-
|
|
717
|
-
|
|
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)
|
|
718
749
|
|
|
719
750
|
|
|
720
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
|