Make --install-from-img take no file; derive it from the ISO path

--install-from-img now works like --install-from-iso: the installation
media is the ISO path (WIN11_VM_INSTALL_ISO or the downloader's) with
.install.img in place of .iso, which is where
build-windows-install-disk.sh writes it by default. Drop the FILE argument
and WIN11_VM_INSTALL_IMG.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GuofangandClaude Sonnet 5.5 committed 2026-10-18 14:24:09 +08:00
1 parent 69dcfe1d9f
commit b26286c820
2 files changed
+24 -28

No files matched your search

+19 -24
View File
@@ -126,14 +126,14 @@ else:
) )
daemonize = False daemonize = False
install_from_iso = False install_from_iso = False
install_img = Path(env("WIN11_VM_INSTALL_IMG")) if env("WIN11_VM_INSTALL_IMG") else None install_from_img = False
download_only = False download_only = False
extra_args = [] extra_args = []
def usage(stream=sys.stdout): def usage(stream=sys.stdout):
stream.write(f"""\ stream.write(f"""\
Usage: {Path(sys.argv[0]).name} [--daemon] [--download-only] [--install-from-iso | --install-from-img FILE] Usage: {Path(sys.argv[0]).name} [--daemon] [--download-only] [--install-from-iso | --install-from-img]
[--state-dir DIR] [--rdp-port PORT] [--ssh-port PORT] [-- QEMU_ARGUMENT ...] [--state-dir DIR] [--rdp-port PORT] [--ssh-port PORT] [-- QEMU_ARGUMENT ...]
If the system disk (DIR/disk.qcow2, see --state-dir) is missing, create it from If the system disk (DIR/disk.qcow2, see --state-dir) is missing, create it from
@@ -151,12 +151,11 @@ Options:
--download-only Download the VirtIO tools ISO if it is missing, then exit --download-only Download the VirtIO tools ISO if it is missing, then exit
(the Windows ISO and base QCOW2 are supplied manually) (the Windows ISO and base QCOW2 are supplied manually)
--install-from-iso Install from ISO when the system disk is missing --install-from-iso Install from ISO when the system disk is missing
--install-from-img FILE --install-from-img Like --install-from-iso, but install from the disk image
Install from a disk image made by made by vm-images/build-windows-install-disk.sh, which
vm-images/build-windows-install-disk.sh instead of the ISO is the ISO path ending in .install.img instead of .iso.
(implies --install-from-iso). It is attached as an NVMe It is attached as an NVMe disk, much faster than the
disk, much faster than the emulated USB CD-ROM, and is emulated USB CD-ROM, and is never modified
never modified (overrides WIN11_VM_INSTALL_IMG)
--state-dir DIR Directory for the VM disk, seed ISO and runtime files --state-dir DIR Directory for the VM disk, seed ISO and runtime files
(default: .vm/windows11; overrides WIN11_VM_STATE_DIR) (default: .vm/windows11; overrides WIN11_VM_STATE_DIR)
--rdp-port PORT Host port forwarded to guest RDP (default: 3389; --rdp-port PORT Host port forwarded to guest RDP (default: 3389;
@@ -168,7 +167,7 @@ Options:
Environment variables: Environment variables:
WIN11_VM_BASE_IMAGE Windows 11 base QCOW2 image (default: beside shared images) WIN11_VM_BASE_IMAGE Windows 11 base QCOW2 image (default: beside shared images)
WIN11_VM_INSTALL_ISO Windows 11 installation ISO used with --install-from-iso WIN11_VM_INSTALL_ISO Windows 11 installation ISO used with --install-from-iso
WIN11_VM_INSTALL_IMG Installation disk image used instead of the ISO (--install-from-img uses the same path ending in .install.img)
WIN11_VM_TOOLS_ISO VirtIO Windows tools ISO (default: resolved by shared image helper) WIN11_VM_TOOLS_ISO VirtIO Windows tools ISO (default: resolved by shared image helper)
WIN11_VM_RDP_PORT Host RDP port (default: 3389) WIN11_VM_RDP_PORT Host RDP port (default: 3389)
WIN11_VM_SSH_PORT Host SSH port (default: 2222) WIN11_VM_SSH_PORT Host SSH port (default: 2222)
@@ -194,11 +193,7 @@ while args:
elif arg == "--install-from-iso": elif arg == "--install-from-iso":
install_from_iso = True install_from_iso = True
elif arg == "--install-from-img": elif arg == "--install-from-img":
if not args: install_from_img = True
die(f"{arg} requires a file argument.", 2)
install_img = Path(args.pop(0))
elif arg.startswith("--install-from-img="):
install_img = Path(arg.split("=", 1)[1])
elif arg == "--state-dir": elif arg == "--state-dir":
if not args: if not args:
die(f"{arg} requires a directory argument.", 2) die(f"{arg} requires a directory argument.", 2)
@@ -228,7 +223,7 @@ while args:
usage(sys.stderr) usage(sys.stderr)
sys.exit(2) sys.exit(2)
if install_img: if install_from_img:
install_from_iso = True install_from_iso = True
if download_only: if download_only:
@@ -263,10 +258,11 @@ if not disk_image.is_file():
installing_from_iso = install_from_iso installing_from_iso = install_from_iso
image_downloader = find_image_downloader() image_downloader = find_image_downloader()
if install_from_iso: if install_from_iso:
# The installation disk image replaces the ISO, which is then not needed. install_iso = Path(
install_iso = None if install_img else Path(
env("WIN11_VM_INSTALL_ISO") env("WIN11_VM_INSTALL_ISO")
or capture([str(image_downloader), "--print-path", "windows11", "--iso"])) or capture([str(image_downloader), "--print-path", "windows11", "--iso"]))
if install_from_img:
install_iso = install_iso.with_suffix(".install.img")
uses_shared_tools_iso = False uses_shared_tools_iso = False
if env("WIN11_VM_TOOLS_ISO"): if env("WIN11_VM_TOOLS_ISO"):
tools_iso = Path(env("WIN11_VM_TOOLS_ISO")) tools_iso = Path(env("WIN11_VM_TOOLS_ISO"))
@@ -282,12 +278,11 @@ if shutil.which(qemu_binary) is None:
if installing: if installing:
if shutil.which("qemu-img") is None: if shutil.which("qemu-img") is None:
die("qemu-img is not installed.") die("qemu-img is not installed.")
if install_img: if installing_from_iso:
if not install_img.is_file():
die(f"Windows 11 installation disk image was not found: {install_img}\n"
"Build it with vm-images/build-windows-install-disk.sh ISO OUTPUT.img")
elif installing_from_iso:
if not install_iso.is_file(): if not install_iso.is_file():
if install_from_img:
die(f"Windows 11 installation disk image was not found: {install_iso}\n"
"Build it with vm-images/build-windows-install-disk.sh ISO")
die(f"Windows 11 ISO was not found: {install_iso}") die(f"Windows 11 ISO was not found: {install_iso}")
elif not base_image.is_file(): elif not base_image.is_file():
die(f"Windows 11 base QCOW2 image was not found: {base_image}") die(f"Windows 11 base QCOW2 image was not found: {base_image}")
@@ -399,12 +394,12 @@ if installing_from_iso:
device = (f"ide-cd,drive={media_id},bus={ide_bus},bootindex={boot_index}" device = (f"ide-cd,drive={media_id},bus={ide_bus},bootindex={boot_index}"
if host_arch == "amd64" if host_arch == "amd64"
else f"usb-storage,drive={media_id},bootindex={boot_index}") else f"usb-storage,drive={media_id},bootindex={boot_index}")
if media_id == "install_media" and install_img: if media_id == "install_media" and install_from_img:
# snapshot=on: NVMe cannot report write protection, and Windows # snapshot=on: NVMe cannot report write protection, and Windows
# writes to the volume it mounts, so a read-only drive makes it fail. # writes to the volume it mounts, so a read-only drive makes it fail.
# The writes go to a temporary overlay and the image stays unchanged. # The writes go to a temporary overlay and the image stays unchanged.
qemu_args += [ qemu_args += [
"-drive", f"file={install_img},if=none,id={media_id},format=raw,snapshot=on", "-drive", f"file={media_file},if=none,id={media_id},format=raw,snapshot=on",
"-device", f"nvme,drive={media_id},serial=installer,bootindex={boot_index}", "-device", f"nvme,drive={media_id},serial=installer,bootindex={boot_index}",
] ]
continue continue
+5 -4
View File
@@ -8,7 +8,7 @@
- 慢的原因是**安装介质走了模拟的 USB 光驱**(`usb-storage` 挂 ISO):读安装文件平均只有约 4 MB/s。 - 慢的原因是**安装介质走了模拟的 USB 光驱**(`usb-storage` 挂 ISO):读安装文件平均只有约 4 MB/s。
- 把安装介质改成**FAT32 分区里的 NVMe 磁盘镜像**(`install.wim` 拆成 `.swm`)后,读速达到 54 到 92 MB/s - 把安装介质改成**FAT32 分区里的 NVMe 磁盘镜像**(`install.wim` 拆成 `.swm`)后,读速达到 54 到 92 MB/s
(前 7 个采样平均约 74 MB/s),安装在约 80 秒内到 40%,复制阶段约 2 分钟结束。 (前 7 个采样平均约 74 MB/s),安装在约 80 秒内到 40%,复制阶段约 2 分钟结束。
- 方案已接进 `run-windows11.py`:`--install-from-img FILE`,镜像由 `vm-images/build-windows-install-disk.sh` 生成。 - 方案已接进 `run-windows11.py`:`--install-from-img`,镜像由 `vm-images/build-windows-install-disk.sh` 生成。
## 环境 ## 环境
@@ -100,11 +100,12 @@ vm-images/build-windows-install-disk.sh [--force] ISO [OUTPUT.img]
### 启动方式 ### 启动方式
`run-windows11.py` 的 `--install-from-img FILE`(或环境变量 `WIN11_VM_INSTALL_IMG`)用这个镜像做安装介质,隐含 `--install-from-iso`, `run-windows11.py` 的 `--install-from-img` 用这个镜像做安装介质,隐含 `--install-from-iso`。镜像路径是 ISO 路径
此时不再需要找 ISO: (`WIN11_VM_INSTALL_ISO` 或自动查找到的 ISO)把 `.iso` 换成 `.install.img`,也就是 `build-windows-install-disk.sh ISO` 默认生成的位置,
此时不再读取 ISO:
```bash ```bash
./run-windows11.py --install-from-img vm-images/install-iso/Windows11_Client_arm64_en-us_26300_9457.install.img ./run-windows11.py --install-from-img
``` ```
`install_media` 不再作为 `usb-storage` 光驱,而是: `install_media` 不再作为 `usb-storage` 光驱,而是: