openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

110 lines
3.5 KiB

#!/usr/bin/env python3
import os
import subprocess
1 month ago
import select
from pathlib import Path
1 month ago
import pyray as rl
# NOTE: Do NOT import anything here that needs be built (e.g. params)
from openpilot.common.basedir import BASEDIR
from openpilot.system.hardware import HARDWARE, AGNOS
from openpilot.common.swaglog import cloudlog, add_file_handler
from openpilot.system.version import get_build_metadata
1 month ago
from openpilot.system.ui.lib.application import gui_app
from openpilot.system.ui.spinner import Spinner
from openpilot.system.ui.text import TextWindow
MAX_CACHE_SIZE = 4e9 if "CI" in os.environ else 2e9
CACHE_DIR = Path("/data/scons_cache" if AGNOS else "/tmp/scons_cache")
3 months ago
TOTAL_SCONS_NODES = 3130
MAX_BUILD_PROGRESS = 100
1 month ago
def build(dirty: bool = False, minimal: bool = False) -> None:
env = os.environ.copy()
env['SCONS_PROGRESS'] = "1"
1 month ago
nproc = os.cpu_count() or 2
extra_args = ["--minimal"] if minimal else []
1 month ago
CI = os.getenv("CI") is not None
if AGNOS:
HARDWARE.set_power_save(False)
os.sched_setaffinity(0, range(8)) # ensure we can use the isolcpus cores
# building with all cores can result in using too
# much memory, so retry with less parallelism
1 month ago
if not CI:
gui_app.init_window("Spinner")
spinner = Spinner()
compile_output: list[bytes] = []
for n in (nproc, nproc/2, 1):
compile_output.clear()
scons: subprocess.Popen = subprocess.Popen(["scons", f"-j{int(n)}", "--cache-populate", *extra_args], cwd=BASEDIR, env=env, stderr=subprocess.PIPE)
assert scons.stderr is not None
1 month ago
os.set_blocking(scons.stderr.fileno(), False) # Non-blocking reads
# Read progress from stderr and update spinner
1 month ago
if not CI:
spinner.set_text("0")
while scons.poll() is None:
try:
1 month ago
if not CI:
rl.begin_drawing()
rl.clear_background(rl.BLACK)
spinner.render()
rl.end_drawing()
1 month ago
if scons.stderr in select.select([scons.stderr], [], [], 0.02)[0]:
line = scons.stderr.readline()
if not line:
continue
line = line.rstrip()
prefix = b'progress: '
if line.startswith(prefix):
1 month ago
if not CI:
i = int(line[len(prefix):])
spinner.set_text(str(int(MAX_BUILD_PROGRESS * min(1., i / TOTAL_SCONS_NODES))))
elif len(line):
compile_output.append(line)
print(line.decode('utf8', 'replace'))
except Exception:
pass
if scons.returncode == 0:
break
if scons.returncode != 0:
# Read remaining output
if scons.stderr is not None:
1 month ago
compile_output += [line for line in scons.stderr.read().split(b'\n') if not line.startswith(b'progress')]
# Build failed log errors
error_s = b"\n".join(compile_output).decode('utf8', 'replace')
add_file_handler(cloudlog)
cloudlog.error("scons build failed\n" + error_s)
# Show TextWindow
1 month ago
if not CI:
1 month ago
text_window = TextWindow("openpilot failed to build\n \n" + error_s)
while True:
rl.begin_drawing()
rl.clear_background(rl.BLACK)
text_window.render()
rl.end_drawing()
exit(1)
# enforce max cache size
cache_files = [f for f in CACHE_DIR.rglob('*') if f.is_file()]
cache_files.sort(key=lambda f: f.stat().st_mtime)
cache_size = sum(f.stat().st_size for f in cache_files)
for f in cache_files:
if cache_size < MAX_CACHE_SIZE:
break
cache_size -= f.stat().st_size
f.unlink()
if __name__ == "__main__":
build_metadata = get_build_metadata()
1 month ago
build(build_metadata.openpilot.is_dirty, minimal = AGNOS)