updates
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
__pycache__/
|
||||
CLAUDE.md
|
||||
+25
-26
@@ -61,6 +61,7 @@ class VMConfig:
|
||||
memory: int = 1024
|
||||
cpus: int = 2
|
||||
disk: str = ""
|
||||
disk_fmt: str = "qcow2"
|
||||
cdrom: str = ""
|
||||
arch: str = "x86_64"
|
||||
network: str = "user"
|
||||
@@ -189,7 +190,7 @@ class VMManager:
|
||||
vm = self.vms.get(name)
|
||||
if not vm:
|
||||
return "Not found"
|
||||
if vm.status == "running":
|
||||
if vm.status in ("running", "paused"):
|
||||
return "Stop VM first"
|
||||
del self.vms[name]
|
||||
self._save()
|
||||
@@ -199,7 +200,7 @@ class VMManager:
|
||||
vm = self.vms.get(name)
|
||||
if not vm:
|
||||
return "Not found"
|
||||
if vm.status == "running":
|
||||
if vm.status in ("running", "paused"):
|
||||
return "Stop VM first"
|
||||
vm.config = cfg
|
||||
self._save()
|
||||
@@ -221,7 +222,7 @@ class VMManager:
|
||||
cmd += ["-drive", f"if=pflash,format=raw,readonly=on,file={ovmf}"]
|
||||
|
||||
if cfg.disk:
|
||||
cmd += ["-drive", f"file={cfg.disk},format=qcow2,if=virtio"]
|
||||
cmd += ["-drive", f"file={cfg.disk},format={cfg.disk_fmt},if=virtio"]
|
||||
|
||||
if cfg.cdrom:
|
||||
cmd += ["-cdrom", cfg.cdrom]
|
||||
@@ -285,8 +286,8 @@ class VMManager:
|
||||
vm = self.vms.get(name)
|
||||
if not vm:
|
||||
return "Not found"
|
||||
if vm.status == "running":
|
||||
return "Already running"
|
||||
if vm.status in ("running", "paused"):
|
||||
return "Already running or paused"
|
||||
cmd, sock = self.build_cmd(vm.config)
|
||||
try:
|
||||
Path(sock).unlink(missing_ok=True)
|
||||
@@ -610,7 +611,6 @@ class VMManager:
|
||||
# strip ANSI escape sequences (e.g. cursor movement, colour codes)
|
||||
import re as _re
|
||||
text = _re.sub(r'\x1b\[[0-9;]*[A-Za-z]', '', text)
|
||||
text = _re.sub(r'\x1b\[[0-9;]*m', '', text)
|
||||
text = text.replace("(qemu)", "").strip()
|
||||
return text or "(ok)"
|
||||
except Exception as e:
|
||||
@@ -627,6 +627,7 @@ class VMManager:
|
||||
vm = self.vms.get(name)
|
||||
if vm:
|
||||
vm.status = "paused"
|
||||
self._save_runtime()
|
||||
return ""
|
||||
|
||||
def monitor_resume(self, name: str) -> str:
|
||||
@@ -636,6 +637,7 @@ class VMManager:
|
||||
vm = self.vms.get(name)
|
||||
if vm:
|
||||
vm.status = "running"
|
||||
self._save_runtime()
|
||||
return ""
|
||||
|
||||
def monitor_reset(self, name: str) -> str:
|
||||
@@ -713,18 +715,13 @@ class VMManager:
|
||||
|
||||
# probe with qemu-img info
|
||||
info = self.disk_info(disk_path)
|
||||
# build config — use detected format in extra_args if not qcow2
|
||||
fmt = info.get("format", "qcow2") if "error" not in info else "qcow2"
|
||||
|
||||
cfg = VMConfig(
|
||||
name = vm_name,
|
||||
disk = disk_path,
|
||||
extra_args = f"-drive file={disk_path},format={fmt},if=virtio" if fmt != "qcow2" else "",
|
||||
name = vm_name,
|
||||
disk = disk_path,
|
||||
disk_fmt = fmt,
|
||||
)
|
||||
# if format is not qcow2, use raw drive and clear the standard disk field
|
||||
if fmt != "qcow2":
|
||||
cfg.disk = ""
|
||||
cfg.extra_args = f"-drive file={disk_path},format={fmt},if=virtio"
|
||||
|
||||
self.vms[vm_name] = VMState(config=cfg)
|
||||
self._save()
|
||||
@@ -1066,6 +1063,7 @@ def vm_form_modal(stdscr, cfg: Optional[VMConfig] = None) -> Optional[VMConfig]:
|
||||
memory = int(values["memory"] or 1024),
|
||||
cpus = int(values["cpus"] or 2),
|
||||
disk = values["disk"].strip(),
|
||||
disk_fmt = cfg.disk_fmt,
|
||||
cdrom = values["cdrom"].strip(),
|
||||
arch = values["arch"],
|
||||
network = values["network"],
|
||||
@@ -1382,7 +1380,7 @@ def disk_mgmt_modal(stdscr, mgr: VMManager, vm_state) -> str:
|
||||
else:
|
||||
if not cfg.disk:
|
||||
cfg.disk = path_raw
|
||||
mgr.update(cfg.name, cfg)
|
||||
mgr._save()
|
||||
msg = f"Created {path_raw} ({gb} GiB)"
|
||||
info = _load_info()
|
||||
|
||||
@@ -1664,7 +1662,8 @@ def portfwd_modal(stdscr, mgr: VMManager, vm_state) -> str:
|
||||
|
||||
def _save():
|
||||
cfg.portfwds = [dict(r) for r in rules]
|
||||
mgr.update(cfg.name, cfg)
|
||||
err = mgr.update(cfg.name, cfg)
|
||||
return err
|
||||
|
||||
while True:
|
||||
win.erase()
|
||||
@@ -1734,8 +1733,10 @@ def portfwd_modal(stdscr, mgr: VMManager, vm_state) -> str:
|
||||
|
||||
if _is_esc(ch):
|
||||
_flush_esc(win)
|
||||
_save()
|
||||
err = _save()
|
||||
_close_modal(win, stdscr)
|
||||
if err:
|
||||
return f"Error: {err}"
|
||||
return f"Saved {len(rules)} rule(s)." if rules else "No rules."
|
||||
|
||||
elif ch == curses.KEY_UP:
|
||||
@@ -2214,7 +2215,7 @@ class TUI:
|
||||
# tabs: 0=Info 1=Command 2=Console 3=Disk 4=Snapshots 5=Monitor
|
||||
self.tab = 0
|
||||
self.log_off = 0
|
||||
self.msg = "Ready | n=new Tab=switch tab q=quit"
|
||||
self.msg = "Ready"
|
||||
self.msg_ok = True
|
||||
self.last_poll = 0.0
|
||||
|
||||
@@ -2254,7 +2255,8 @@ class TUI:
|
||||
("s","start"), ("k","stop"), ("F","force kill"),
|
||||
("g","ACPI"), ("z","pause"), ("~","monitor ~"),
|
||||
("d","disk"), ("p","snaps"), ("f","portfwd"),
|
||||
("x","eject"), ("q","quit"),
|
||||
("x","eject"),
|
||||
("Tab","switch tab"), ("q","quit"),
|
||||
]
|
||||
hy = sh - len(hints) - 2
|
||||
for key, act in hints:
|
||||
@@ -2379,7 +2381,7 @@ class TUI:
|
||||
elif base < y0 + h and cfg.network == "user":
|
||||
try:
|
||||
scr.addstr(base, x0, f"{'Port Fwds':<16}", curses.color_pair(6))
|
||||
scr.addstr(base, x0 + 16, "(none — press F to add)", curses.color_pair(6))
|
||||
scr.addstr(base, x0 + 16, "(none — press f to add)", curses.color_pair(6))
|
||||
except curses.error:
|
||||
pass
|
||||
|
||||
@@ -2445,7 +2447,7 @@ class TUI:
|
||||
try:
|
||||
scr.addstr(row, x0, "No disk configured.", curses.color_pair(6))
|
||||
row += 1
|
||||
scr.addstr(row, x0, "Press 'm' to open Disk Management and create one.",
|
||||
scr.addstr(row, x0, "Press 'd' to open Disk Management and create one.",
|
||||
curses.color_pair(8))
|
||||
except curses.error:
|
||||
pass
|
||||
@@ -2456,7 +2458,7 @@ class TUI:
|
||||
if not p.exists():
|
||||
addrow("Status", "FILE NOT FOUND", curses.color_pair(5))
|
||||
try:
|
||||
scr.addstr(row+1, x0, "Press 'm' > Create to make the disk image.",
|
||||
scr.addstr(row+1, x0, "Press 'd' > Create to make the disk image.",
|
||||
curses.color_pair(8))
|
||||
except curses.error:
|
||||
pass
|
||||
@@ -2481,7 +2483,7 @@ class TUI:
|
||||
try:
|
||||
scr.addstr(row, x0, "-" * min(w-1, 50), curses.color_pair(6))
|
||||
row += 1
|
||||
scr.addstr(row, x0, "Press 'm' to manage: create / resize / convert / delete",
|
||||
scr.addstr(row, x0, "Press 'd' to manage: create / resize / convert / delete",
|
||||
curses.color_pair(8))
|
||||
except curses.error:
|
||||
pass
|
||||
@@ -2615,9 +2617,6 @@ class TUI:
|
||||
|
||||
if ch in (ord("q"), ord("Q")):
|
||||
return False
|
||||
if _is_esc(ch):
|
||||
return False
|
||||
|
||||
elif ch == curses.KEY_DOWN:
|
||||
self.sel = clamp(self.sel + 1, 0, max(0, len(names)-1))
|
||||
self.log_off = 0
|
||||
|
||||
Reference in New Issue
Block a user