Skip to content

Commit fdfd6ce

Browse files
committed
Support file:// mirrors
Spawns a simple HTTP server to host the mirror. Useful for testing mirror support or CI in chroot or bwrap modes.
1 parent a03c28f commit fdfd6ce

File tree

4 files changed

+59
-10
lines changed

4 files changed

+59
-10
lines changed

download-distfiles.sh

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,13 @@ download_source() {
3737
check_source() {
3838
local distfiles="${1}"
3939
local url="${2}"
40-
local checksum="${3}"
41-
local fname="${4}"
40+
shift 2
41+
if [[ "${url}" == git://* ]]; then
42+
url="${1}"
43+
shift
44+
fi
45+
local checksum="${1}"
46+
local fname="${2}"
4247
# Default to basename of url if not given
4348
fname="${fname:-$(basename "${url}")}"
4449

lib/simple_mirror.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import http.server
2+
import socketserver
3+
4+
class SimpleMirror(socketserver.TCPServer):
5+
def __init__(self, directory: str):
6+
self.directory = directory
7+
super().__init__(("127.0.0.1", 0), self._handler)
8+
9+
@property
10+
def port(self):
11+
return self.server_address[1]
12+
13+
def _handler(self, *args, **kwargs):
14+
return http.server.SimpleHTTPRequestHandler(*args, directory=self.directory, **kwargs)

lib/utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import subprocess
1313
import sys
1414

15-
def run(*args, **kwargs):
15+
def run(*args, cleanup=None, **kwargs):
1616
"""A small wrapper around subprocess.run"""
1717
arguments = [str(arg) for arg in args if arg is not None]
1818

@@ -23,6 +23,8 @@ def run(*args, **kwargs):
2323
return subprocess.run(arguments, check=True, **kwargs)
2424
except subprocess.CalledProcessError:
2525
print("Bootstrapping failed")
26+
if cleanup:
27+
cleanup()
2628
sys.exit(1)
2729

2830
def run_as_root(*args, **kwargs):

rootfs.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@
1616

1717
import argparse
1818
import os
19+
import signal
20+
import threading
1921

20-
from lib.utils import run, run_as_root
21-
from lib.target import Target
2222
from lib.generator import Generator, stage0_arch_map
23+
from lib.simple_mirror import SimpleMirror
24+
from lib.target import Target
25+
from lib.utils import run, run_as_root
2326

2427
def create_configuration_file(args):
2528
"""
@@ -177,6 +180,19 @@ def check_types():
177180
# Set constant umask
178181
os.umask(0o022)
179182

183+
# file:// mirrors
184+
mirror_servers = []
185+
if args.mirrors:
186+
for i, mirror in enumerate(args.mirrors):
187+
if mirror.startswith("file://"):
188+
path = mirror.removeprefix("file://")
189+
if not path.startswith("/"):
190+
raise ValueError("A file:// mirror must be an absolute path.")
191+
192+
server = SimpleMirror(path)
193+
args.mirrors[i] = f"http://127.0.0.1:{server.port}"
194+
mirror_servers.append(server)
195+
180196
# bootstrap.cfg
181197
try:
182198
os.remove(os.path.join('steps', 'bootstrap.cfg'))
@@ -193,15 +209,25 @@ def check_types():
193209
if args.tmpfs:
194210
target.tmpfs(size=args.tmpfs_size)
195211

212+
for server in mirror_servers:
213+
thread = threading.Thread(target=server.serve_forever)
214+
thread.start()
215+
216+
def cleanup(*_):
217+
for server in mirror_servers:
218+
server.shutdown()
219+
signal.signal(signal.SIGINT, cleanup)
220+
196221
generator = Generator(arch=args.arch,
197222
external_sources=args.external_sources,
198223
repo_path=args.repo,
199224
early_preseed=args.early_preseed,
200225
mirrors=args.mirrors)
201226

202-
bootstrap(args, generator, target, args.target_size)
227+
bootstrap(args, generator, target, args.target_size, cleanup)
228+
cleanup()
203229

204-
def bootstrap(args, generator, target, size):
230+
def bootstrap(args, generator, target, size, cleanup):
205231
"""Kick off bootstrap process."""
206232
print(f"Bootstrapping {args.arch}", flush=True)
207233
if args.chroot:
@@ -216,7 +242,8 @@ def bootstrap(args, generator, target, size):
216242

217243
arch = stage0_arch_map.get(args.arch, args.arch)
218244
init = os.path.join(os.sep, 'bootstrap-seeds', 'POSIX', arch, 'kaem-optional-seed')
219-
run_as_root('env', '-i', 'PATH=/bin', chroot_binary, generator.target_dir, init)
245+
run_as_root('env', '-i', 'PATH=/bin', chroot_binary, generator.target_dir, init,
246+
cleanup=cleanup)
220247

221248
elif args.bwrap:
222249
init = '/init'
@@ -245,7 +272,8 @@ def bootstrap(args, generator, target, size):
245272
'--proc', '/proc',
246273
'--bind', '/sys', '/sys',
247274
'--tmpfs', '/tmp',
248-
init)
275+
init,
276+
cleanup=cleanup)
249277

250278
elif args.bare_metal:
251279
if args.kernel:
@@ -303,7 +331,7 @@ def bootstrap(args, generator, target, size):
303331
]
304332
if not args.interactive:
305333
arg_list += ['-no-reboot', '-nographic']
306-
run(args.qemu_cmd, *arg_list)
334+
run(args.qemu_cmd, *arg_list, cleanup=cleanup)
307335

308336
if __name__ == "__main__":
309337
main()

0 commit comments

Comments
 (0)