Skip to content

Commit ba5c0bd

Browse files
committed
feat: compress repo runtime snapshots
1 parent a5b5366 commit ba5c0bd

14 files changed

Lines changed: 136 additions & 49 deletions

README.en.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ This repository does one specific thing: on a modern host, it builds the two run
77
The repository no longer stores third-party runtime images. The repository now includes self-built runtime image snapshots under version control:
88

99
- `images/bootimage-0.12-hd`
10-
- `images/hdc-0.12.img`
10+
- `images/hdc-0.12.img.xz`
1111

1212
The same source-build workflow also produces local working images:
1313

@@ -23,7 +23,7 @@ The build and runtime flow is:
2323
- compile the kernel boot image
2424
- compile the repo-owned minimal userland programs `/bin/sh` and `/bin/ls`
2525
- build a Minix v1 root filesystem from repo manifests
26-
- generate the repo-bundled images `images/bootimage-0.12-hd` and `images/hdc-0.12.img`
26+
- generate the repo-bundled images `images/bootimage-0.12-hd` and `images/hdc-0.12.img.xz`
2727
- boot QEMU
2828
- reach `[/usr/root]#`
2929
- run `ls`
@@ -113,7 +113,7 @@ Windows CMD:
113113
scripts\run.cmd
114114
```
115115

116-
This entrypoint uses the committed images in `images/` directly and does not rebuild first. On macOS / Ubuntu it keeps the current terminal-based interactive flow; on Windows it already uses a visible GUI window.
116+
This entrypoint uses the committed snapshots in `images/` directly and does not rebuild first. The hard disk image is automatically unpacked to `out/repo-images/hdc-0.12.img` before launch. On macOS / Ubuntu it keeps the current terminal-based interactive flow; on Windows it already uses a visible GUI window.
117117

118118
### 4. Open A Visible QEMU Window And Interact Manually
119119

@@ -161,7 +161,7 @@ Windows CMD:
161161
scripts\build-and-run.cmd
162162
```
163163

164-
This entrypoint forces a rebuild, syncs the new images into `images/`, and then starts QEMU.
164+
This entrypoint forces a rebuild, syncs the new images into `images/`, stores the hard disk image as the compressed snapshot `images/hdc-0.12.img.xz`, and then starts QEMU.
165165

166166
If you want the flow to start from compilation and still end in a visible interactive QEMU window, run:
167167

@@ -299,7 +299,8 @@ Important generated artifacts:
299299
- `rebuild/out/images/bootimage-0.12-hd`
300300
- `rebuild/out/images/hdc-0.12.img`
301301
- `images/bootimage-0.12-hd`
302-
- `images/hdc-0.12.img`
302+
- `images/hdc-0.12.img.xz`
303+
- `out/repo-images/hdc-0.12.img`
303304
- `out/verify/screen.txt`
304305
- `out/verify-userland/screen.txt`
305306
- `out/run/boot.img`
@@ -316,7 +317,7 @@ The `rebuild/` directory owns the full source-to-image pipeline:
316317
6. create directories, device nodes, and boot files from `rebuild/rootfs/manifest/`
317318
7. build a Minix v1 root filesystem that Linux 0.12 can mount
318319
8. assemble `hdc-0.12.img`
319-
9. sync new images into the repo-managed `images/` directory when requested
320+
9. sync the new boot image and compressed hard disk snapshot into the repo-managed `images/` directory when requested
320321
10. boot QEMU, scrape VGA text, and inject keys to complete verification
321322

322323
This pipeline intentionally builds only the smallest system required by the repo. It does not try to recreate a full historical Linux 0.12 distribution.
@@ -340,7 +341,7 @@ The current standalone userland binaries are:
340341
- `scripts/`
341342
host-specific entry scripts
342343
- `images/`
343-
committed snapshots of the self-built runtime images
344+
committed snapshots of the self-built runtime images, with the hard disk stored in compressed form
344345
- `rebuild/driver.py`
345346
source build, runtime, and verification entrypoint
346347
- `rebuild/container/build_images.sh`
@@ -363,8 +364,8 @@ The current standalone userland binaries are:
363364
## Runtime Notes
364365

365366
- The boot image is shorter than 1.44MB, so the driver pads it into a full floppy image before launch
366-
- `scripts/run.*` uses the committed images in `images/` by default
367-
- `scripts/run-window.*` uses the committed images in `images/` and opens a visible QEMU window
367+
- `scripts/run.*` uses the committed snapshots in `images/` by default and unpacks the hard disk image into `out/repo-images/`
368+
- `scripts/run-window.*` uses the committed snapshots in `images/`, unpacks the hard disk image into `out/repo-images/`, and opens a visible QEMU window
368369
- `scripts/build-and-run.*` rebuilds from source and refreshes `images/`
369370
- `scripts/build-and-run-window.*` rebuilds from source, refreshes `images/`, and opens a visible QEMU window
370371
- QEMU always starts with `-snapshot`, so repeated runs do not mutate `rebuild/out/images/hdc-0.12.img`

README.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
仓库当前不再保存第三方运行时镜像。仓库里提交的是本项目自己编译出来的镜像快照:
88

99
- `images/bootimage-0.12-hd`
10-
- `images/hdc-0.12.img`
10+
- `images/hdc-0.12.img.xz`
1111

1212
同一套源码构建链还会在本地生成工作镜像:
1313

@@ -23,7 +23,7 @@
2323
- 编译内核启动镜像
2424
- 编译仓库自带的最小用户态程序 `/bin/sh``/bin/ls`
2525
- 按仓库清单生成 Minix v1 根文件系统
26-
- 生成仓库内置镜像 `images/bootimage-0.12-hd``images/hdc-0.12.img`
26+
- 生成仓库内置镜像 `images/bootimage-0.12-hd``images/hdc-0.12.img.xz`
2727
- 启动 QEMU
2828
- 进入 `[/usr/root]#`
2929
- 执行 `ls`
@@ -113,7 +113,7 @@ Windows CMD:
113113
scripts\run.cmd
114114
```
115115

116-
这条入口直接使用仓库里的 `images/` 镜像,不会先重编源码。macOS / Ubuntu 下它保留当前的终端交互方式;Windows 下本来就是图形窗口。
116+
这条入口直接使用仓库里的 `images/` 快照,不会先重编源码。系统硬盘镜像会先自动解包到 `out/repo-images/hdc-0.12.img`,然后再启动。macOS / Ubuntu 下它保留当前的终端交互方式;Windows 下本来就是图形窗口。
117117

118118
### 4. 弹出可见的 QEMU 窗口并手动操作
119119

@@ -161,7 +161,7 @@ Windows CMD:
161161
scripts\build-and-run.cmd
162162
```
163163

164-
这条入口会强制重新编译,完成后把新的镜像同步到 `images/`,然后启动 QEMU。
164+
这条入口会强制重新编译,完成后把新的镜像同步到 `images/`其中硬盘镜像会以压缩快照形式写成 `images/hdc-0.12.img.xz`然后启动 QEMU。
165165

166166
如果你既要“从编译开始”,又要最后看到可交互的 QEMU 窗口,运行:
167167

@@ -299,7 +299,8 @@ python3 rebuild/driver.py run
299299
- `rebuild/out/images/bootimage-0.12-hd`
300300
- `rebuild/out/images/hdc-0.12.img`
301301
- `images/bootimage-0.12-hd`
302-
- `images/hdc-0.12.img`
302+
- `images/hdc-0.12.img.xz`
303+
- `out/repo-images/hdc-0.12.img`
303304
- `out/verify/screen.txt`
304305
- `out/verify-userland/screen.txt`
305306
- `out/run/boot.img`
@@ -316,7 +317,7 @@ python3 rebuild/driver.py run
316317
6. 根据 `rebuild/rootfs/manifest/` 创建目录、设备节点和启动脚本
317318
7. 生成 Linux 0.12 可挂载的 Minix v1 根文件系统
318319
8. 组装成 `hdc-0.12.img`
319-
9. 按需把新镜像同步到仓库的 `images/`
320+
9. 按需把新的启动镜像和压缩后的系统镜像同步到仓库的 `images/`
320321
10. 启动 QEMU,抓取 VGA 文本,并自动向 guest 发送按键完成验证
321322

322323
这条链路当前只实现“最小可运行系统”,不尝试复刻一个完整的历史 Linux 0.12 发行版。
@@ -340,7 +341,7 @@ python3 rebuild/driver.py run
340341
- `scripts/`
341342
不同宿主机的入口脚本
342343
- `images/`
343-
提交到仓库中的自编译运行镜像快照
344+
提交到仓库中的自编译运行镜像快照,其中系统镜像以压缩形式保存
344345
- `rebuild/driver.py`
345346
源码构建、运行和验证入口
346347
- `rebuild/container/build_images.sh`
@@ -363,8 +364,8 @@ python3 rebuild/driver.py run
363364
## 运行说明
364365

365366
- 启动镜像本身不足 1.44MB,驱动会在启动前补齐成标准软盘镜像
366-
- `scripts/run.*` 默认直接使用仓库里的 `images/`
367-
- `scripts/run-window.*` 默认直接使用仓库里的 `images/`,并弹出可见的 QEMU 窗口
367+
- `scripts/run.*` 默认直接使用仓库里的 `images/` 快照,并在 `out/repo-images/` 里自动解包系统镜像
368+
- `scripts/run-window.*` 默认直接使用仓库里的 `images/` 快照,并在 `out/repo-images/` 里自动解包系统镜像后弹出可见的 QEMU 窗口
368369
- `scripts/build-and-run.*` 会重编源码并刷新 `images/`
369370
- `scripts/build-and-run-window.*` 会重编源码、刷新 `images/`,然后弹出可见的 QEMU 窗口
370371
- QEMU 始终以 `-snapshot` 启动,所以重复运行不会改写 `rebuild/out/images/hdc-0.12.img`

images/README.en.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22

33
[中文 README](./README.md)
44

5-
This directory stores the repo-managed runtime image snapshots. They are not third-party downloads. They are built by this repository's own `rebuild/` pipeline and then synced here.
5+
This directory stores the repo-managed runtime image snapshots. They are not third-party downloads. They are built by this repository's own `rebuild/` pipeline and then synced here. To keep the repository smaller, the hard disk image is stored as a compressed snapshot.
66

77
## Current Files
88

99
- `bootimage-0.12-hd`
1010
Linux 0.12 boot image
11-
- `hdc-0.12.img`
12-
Linux 0.12 minimal system hard disk image
11+
- `hdc-0.12.img.xz`
12+
compressed snapshot of the Linux 0.12 minimal system hard disk image
1313

1414
## Usage
1515

16-
- `scripts/run.*` boots directly from the images here
17-
- `scripts/run-window.*` boots directly from the images here and opens a visible window
18-
- `scripts/build-and-run.*` and `scripts/build-and-run-window.*` rebuild first, then refresh the images here
16+
- `scripts/run.*` boots from the snapshots here and unpacks the hard disk image into `out/repo-images/`
17+
- `scripts/run-window.*` boots from the snapshots here, unpacks the hard disk image into `out/repo-images/`, and opens a visible window
18+
- `scripts/build-and-run.*` and `scripts/build-and-run-window.*` rebuild first, then refresh the snapshots here

images/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22

33
[English README](./README.en.md)
44

5-
这个目录保存受版本控制的运行镜像快照。它们不是第三方下载镜像,而是本仓库通过 `rebuild/` 流程自行构建出来并同步到这里的结果。
5+
这个目录保存受版本控制的运行镜像快照。它们不是第三方下载镜像,而是本仓库通过 `rebuild/` 流程自行构建出来并同步到这里的结果。为了减小仓库体积,系统硬盘镜像以压缩快照形式保存。
66

77
## 当前文件
88

99
- `bootimage-0.12-hd`
1010
Linux 0.12 启动镜像
11-
- `hdc-0.12.img`
12-
Linux 0.12 最小系统硬盘镜像
11+
- `hdc-0.12.img.xz`
12+
Linux 0.12 最小系统硬盘镜像的压缩快照
1313

1414
## 使用方式
1515

16-
- `scripts/run.*` 直接使用这里的镜像启动
17-
- `scripts/run-window.*` 直接使用这里的镜像并弹出可见窗口
18-
- `scripts/build-and-run.*``scripts/build-and-run-window.*` 会先重编,再刷新这里的镜像
16+
- `scripts/run.*` 会直接使用这里的快照,并把系统镜像自动解包到 `out/repo-images/`
17+
- `scripts/run-window.*` 会直接使用这里的快照,并把系统镜像自动解包到 `out/repo-images/` 后弹出可见窗口
18+
- `scripts/build-and-run.*``scripts/build-and-run-window.*` 会先重编,再刷新这里的镜像快照

images/hdc-0.12.img

-59.6 MB
Binary file not shown.

images/hdc-0.12.img.xz

11.4 KB
Binary file not shown.

rebuild/README.en.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
- build `rebuild/out/images/bootimage-0.12-hd`
1010
- build `rebuild/out/images/hdc-0.12.img`
1111
- use `driver.py` to orchestrate Docker and QEMU for build, boot, and verification
12-
- sync built images into the repo-level `images/` directory when requested
12+
- sync the built boot image and compressed hard disk snapshot into the repo-level `images/` directory when requested
1313

1414
## Main Contents
1515

@@ -41,4 +41,4 @@ python3 rebuild/driver.py run-repo-images-window
4141

4242
- this directory owns source build and image assembly
4343
- runtime output under `rebuild/out/` is generated content
44-
- repo-managed image snapshots live in the top-level `images/` directory
44+
- repo-managed image snapshots live in the top-level `images/` directory, with the hard disk stored in compressed form

rebuild/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
- 构建 `rebuild/out/images/bootimage-0.12-hd`
1010
- 构建 `rebuild/out/images/hdc-0.12.img`
1111
- 通过 `driver.py` 调用 Docker 和 QEMU 完成构建、启动与验证
12-
- 在需要时把构建出来的镜像同步到仓库根目录的 `images/`
12+
- 在需要时把构建出来的启动镜像和压缩后的系统镜像同步到仓库根目录的 `images/`
1313

1414
## 主要内容
1515

@@ -41,4 +41,4 @@ python3 rebuild/driver.py run-repo-images-window
4141

4242
- 这里只管理源码构建和镜像装配流程
4343
- 运行时输出在 `rebuild/out/`,属于生成产物
44-
- 受版本控制的镜像快照在仓库根目录 `images/`
44+
- 受版本控制的镜像快照在仓库根目录 `images/`,其中系统镜像以压缩形式保存

rebuild/driver.py

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import argparse
4+
import lzma
45
import os
56
import shutil
67
import subprocess
@@ -24,14 +25,17 @@ class BuildPaths:
2425
boot_image: Path
2526
hard_disk_image: Path
2627
repo_boot_image: Path
27-
repo_hard_disk_image: Path
28+
repo_hard_disk_image_archive: Path
29+
repo_runtime_dir: Path
30+
repo_runtime_hard_disk_image: Path
2831

2932
@classmethod
3033
def from_root(cls, root: Path) -> "BuildPaths":
3134
rebuild_dir = root / "rebuild"
3235
out_dir = rebuild_dir / "out"
3336
images_dir = out_dir / "images"
3437
repo_images_dir = root / "images"
38+
repo_runtime_dir = root / "out" / "repo-images"
3539
return cls(
3640
root=root,
3741
repo_images_dir=repo_images_dir,
@@ -43,7 +47,9 @@ def from_root(cls, root: Path) -> "BuildPaths":
4347
boot_image=images_dir / "bootimage-0.12-hd",
4448
hard_disk_image=images_dir / "hdc-0.12.img",
4549
repo_boot_image=repo_images_dir / "bootimage-0.12-hd",
46-
repo_hard_disk_image=repo_images_dir / "hdc-0.12.img",
50+
repo_hard_disk_image_archive=repo_images_dir / "hdc-0.12.img.xz",
51+
repo_runtime_dir=repo_runtime_dir,
52+
repo_runtime_hard_disk_image=repo_runtime_dir / "hdc-0.12.img",
4753
)
4854

4955

@@ -91,7 +97,7 @@ def verify_environment(paths: BuildPaths, source: str = "rebuild") -> dict[str,
9197
return env
9298
if source == "repo":
9399
env["LINUX012_BOOT_SOURCE_IMAGE"] = str(paths.repo_boot_image)
94-
env["LINUX012_HARD_DISK_IMAGE"] = str(paths.repo_hard_disk_image)
100+
env["LINUX012_HARD_DISK_IMAGE"] = str(paths.repo_runtime_hard_disk_image)
95101
return env
96102
raise ValueError(f"Unsupported runtime image source: {source}")
97103

@@ -153,7 +159,7 @@ def ensure_rebuilt_images(paths: BuildPaths) -> int:
153159

154160

155161
def require_repo_images(paths: BuildPaths) -> bool:
156-
required = [paths.repo_boot_image, paths.repo_hard_disk_image]
162+
required = [paths.repo_boot_image, paths.repo_hard_disk_image_archive]
157163
missing = [path for path in required if not path.exists() or path.stat().st_size == 0]
158164
if not missing:
159165
return True
@@ -164,12 +170,44 @@ def require_repo_images(paths: BuildPaths) -> bool:
164170
return False
165171

166172

173+
def compress_image_snapshot(source: Path, target: Path) -> None:
174+
target.parent.mkdir(parents=True, exist_ok=True)
175+
temporary = target.with_name(f"{target.name}.tmp")
176+
with source.open("rb") as source_handle, lzma.open(temporary, "wb", preset=9 | lzma.PRESET_EXTREME) as target_handle:
177+
shutil.copyfileobj(source_handle, target_handle)
178+
temporary.replace(target)
179+
180+
181+
def extract_image_snapshot(source: Path, target: Path) -> None:
182+
target.parent.mkdir(parents=True, exist_ok=True)
183+
temporary = target.with_name(f"{target.name}.tmp")
184+
with lzma.open(source, "rb") as source_handle, temporary.open("wb") as target_handle:
185+
shutil.copyfileobj(source_handle, target_handle)
186+
temporary.replace(target)
187+
os.utime(target, ns=(source.stat().st_mtime_ns, source.stat().st_mtime_ns))
188+
189+
167190
def sync_repo_images(paths: BuildPaths) -> int:
168191
if not require_rebuilt_images(paths):
169192
return 1
170193
paths.repo_images_dir.mkdir(parents=True, exist_ok=True)
171194
shutil.copy2(paths.boot_image, paths.repo_boot_image)
172-
shutil.copy2(paths.hard_disk_image, paths.repo_hard_disk_image)
195+
compress_image_snapshot(paths.hard_disk_image, paths.repo_hard_disk_image_archive)
196+
legacy_image = paths.repo_images_dir / "hdc-0.12.img"
197+
if legacy_image.exists():
198+
legacy_image.unlink()
199+
return 0
200+
201+
202+
def ensure_repo_runtime_images(paths: BuildPaths) -> int:
203+
if not require_repo_images(paths):
204+
return 1
205+
archive = paths.repo_hard_disk_image_archive
206+
runtime_image = paths.repo_runtime_hard_disk_image
207+
if runtime_image.exists() and runtime_image.stat().st_size > 0:
208+
if runtime_image.stat().st_mtime_ns >= archive.stat().st_mtime_ns:
209+
return 0
210+
extract_image_snapshot(archive, runtime_image)
173211
return 0
174212

175213

@@ -194,7 +232,7 @@ def run_runtime(paths: BuildPaths, mode: str) -> int:
194232

195233

196234
def run_repo_runtime(paths: BuildPaths, mode: str = "run") -> int:
197-
if not require_repo_images(paths):
235+
if ensure_repo_runtime_images(paths) != 0:
198236
return 1
199237
return run_command(
200238
[sys.executable, str(paths.root / "tools" / "qemu_driver.py"), mode],

scripts/README.en.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ This directory stores host-facing one-command entry scripts. Each platform has i
99
- `bootstrap-host.*`
1010
check host dependencies such as Python, QEMU, and Docker
1111
- `run.*`
12-
boot directly from the repo-managed images
12+
boot directly from the repo-managed snapshots and unpack the hard disk image automatically
1313
- `run-window.*`
14-
boot directly from the repo-managed images and open a visible QEMU window
14+
boot directly from the repo-managed snapshots, unpack the hard disk image automatically, and open a visible QEMU window
1515
- `build-and-run.*`
1616
rebuild first, then boot
1717
- `build-and-run-window.*`

0 commit comments

Comments
 (0)