1#!/usr/bin/env python3
2"""Builds snowbound-relay, the Live Share relay, and snowbound-site, which serves the web build and
3the codes' pages (crates/relay), as static executables for each Linux architecture a server
4runs, with the files that deploy them, into target/relay/ by default.
5It ships on its own, outside the app's builds and latest.json; see crates/relay/README.md."""
6import argparse
7import hashlib
8import os
9from pathlib import Path
10import shutil
11import subprocess
12
13ROOT = Path(__file__).resolve().parents[1]
14ARCHITECTURES = ['x86_64', 'aarch64']
15
16
17def build(arch, output):
18 """Linked against Rust's own musl by its own lld, so the file needs nothing of the Linux it
19 runs on."""
20 triple = f'{arch}-unknown-linux-musl'
21 subprocess.run(['rustup', 'target', 'add', triple], check=True, capture_output=True)
22 environment = {**os.environ, f'CARGO_TARGET_{triple.upper().replace("-", "_")}_LINKER': 'rust-lld',
23 'CARGO_PROFILE_RELEASE_STRIP': 'symbols'}
24 subprocess.run(['cargo', 'build', '--locked', '--release', '-p', 'relay', '--target', triple],
25 cwd=ROOT, env=environment, check=True)
26 target = Path(os.environ.get('CARGO_TARGET_DIR') or ROOT / 'target')
27 files = []
28 for name in ['snowbound-relay', 'snowbound-site']:
29 file = output / f'{name}-linux-{arch}'
30 shutil.copy(target / triple / f'release/{name}', file)
31 files.append(file)
32 return files
33
34
35def main():
36 parser = argparse.ArgumentParser(description=__doc__)
37 parser.add_argument('--output', type=Path, default=ROOT / 'target/relay')
38 parser.add_argument('--architectures', nargs='+', choices=ARCHITECTURES, default=ARCHITECTURES)
39 args = parser.parse_args()
40 args.output.mkdir(parents=True, exist_ok=True)
41 files = [file for arch in args.architectures for file in build(arch, args.output)]
42 for deployed in (ROOT / 'crates/relay/deploy').iterdir():
43 shutil.copy(deployed, args.output)
44 shutil.copy(ROOT / 'crates/relay/README.md', args.output)
45 sums = ''.join(f'{hashlib.sha256(file.read_bytes()).hexdigest()} {file.name}\n' for file in files)
46 (args.output / 'SHA256SUMS').write_text(sums)
47 print(f'{args.output}:\n{sums}', end='')
48
49
50if __name__ == '__main__':
51 main()