Sync: commaai/openpilot:master -> sunnypilot/sunnypilot:master

# Conflicts:
#	.gitmodules
#	.lfsconfig
#	opendbc_repo
#	openpilot/selfdrive/modeld/SConscript
#	openpilot/selfdrive/modeld/modeld.py
#	openpilot/selfdrive/ui/mici/layouts/settings/toggles.py
#	openpilot/system/sentry.py
#	panda
#	scripts/lint/lint.sh
#	tinygrad_repo
#	tools/release/build_stripped.sh
#	tools/release/check-submodules.sh
#	uv.lock
This commit is contained in:
discountchubbs
2026-09-16 15:29:27 -07:00
294 changed files with 16448 additions and 10643 deletions
+2 -2
View File
@@ -6,6 +6,6 @@ if [ $# -eq 0 ]; then
fi
BASE="https://github.com/commaai/openpilot/pull/"
PR_NUM="$(echo $1 | grep -o -E '[0-9]+')"
PR_NUM="$(echo "$1" | grep -o -E '[0-9]+')"
curl -L $BASE/$PR_NUM.patch | git apply -3
curl -L "$BASE/$PR_NUM.patch" | git apply -3
+4 -4
View File
@@ -7,10 +7,10 @@ if [ $# -eq 0 ]; then
fi
BASE="https://github.com/commaai/openpilot/pull/"
PR_NUM="$(echo $1 | grep -o -E '[0-9]+')"
PR_NUM="$(echo "$1" | grep -o -E '[0-9]+')"
BRANCH=tmp-pr${PR_NUM}
git branch -D -f $BRANCH || true
git fetch -u -f origin pull/$PR_NUM/head:$BRANCH
git switch $BRANCH
git branch -D -f "$BRANCH" || true
git fetch -u -f origin "pull/$PR_NUM/head:$BRANCH"
git switch "$BRANCH"
git reset --hard FETCH_HEAD
+17 -17
View File
@@ -11,7 +11,7 @@ BRANCH="master"
RUNS="20"
COOKIE_JAR=/tmp/cookies
CRUMB=$(curl -s --cookie-jar $COOKIE_JAR 'https://jenkins.comma.life/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)')
CRUMB=$(curl -s --cookie-jar "$COOKIE_JAR" 'https://jenkins.comma.life/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)')
FIRST_LOOP=1
@@ -25,13 +25,13 @@ function loop() {
if [[ $FIRST_LOOP ]]; then
TEMP_DIR=$(mktemp -d)
GIT_LFS_SKIP_SMUDGE=1 git clone --quiet -b $BRANCH --depth=1 --no-tags git@github.com:commaai/openpilot $TEMP_DIR
git -C $TEMP_DIR checkout --quiet -b $JENKINS_BRANCH
echo "TESTING: $(date)" >> $TEMP_DIR/testing_jenkins
git -C $TEMP_DIR add testing_jenkins
git -C $TEMP_DIR commit --quiet -m "testing"
git -C $TEMP_DIR push --quiet -f origin $JENKINS_BRANCH
rm -rf $TEMP_DIR
GIT_LFS_SKIP_SMUDGE=1 git clone --quiet -b "$BRANCH" --depth=1 --no-tags git@github.com:commaai/openpilot "$TEMP_DIR"
git -C "$TEMP_DIR" checkout --quiet -b "$JENKINS_BRANCH"
echo "TESTING: $(date)" >> "$TEMP_DIR/testing_jenkins"
git -C "$TEMP_DIR" add testing_jenkins
git -C "$TEMP_DIR" commit --quiet -m "testing"
git -C "$TEMP_DIR" push --quiet -f origin "$JENKINS_BRANCH"
rm -rf "$TEMP_DIR"
FIRST_BUILD=1
echo ''
echo 'waiting on Jenkins...'
@@ -40,15 +40,15 @@ function loop() {
FIRST_LOOP=""
fi
FIRST_BUILD=$(curl -s $API_ROUTE/api/json | jq .nextBuildNumber)
FIRST_BUILD=$(curl -s "$API_ROUTE/api/json" | jq .nextBuildNumber)
LAST_BUILD=$((FIRST_BUILD+N-1))
TEST_BUILDS=( $(seq $FIRST_BUILD $LAST_BUILD) )
read -r -a TEST_BUILDS <<< "$(seq -s ' ' "$FIRST_BUILD" "$LAST_BUILD")"
# Start N new builds
for i in ${TEST_BUILDS[@]};
for i in "${TEST_BUILDS[@]}";
do
echo "Starting build $i"
curl -s --output /dev/null --cookie $COOKIE_JAR -H "$CRUMB" -X POST $API_ROUTE/build?delay=0sec
curl -s --output /dev/null --cookie "$COOKIE_JAR" -H "$CRUMB" -X POST "$API_ROUTE/build?delay=0sec"
sleep 5
done
echo ""
@@ -58,14 +58,14 @@ function loop() {
sleep 30
count=0
for i in ${TEST_BUILDS[@]};
for i in "${TEST_BUILDS[@]}";
do
RES=$(curl -s -w "\n%{http_code}" --cookie $COOKIE_JAR -H "$CRUMB" $API_ROUTE/$i/api/json)
RES=$(curl -s -w "\n%{http_code}" --cookie "$COOKIE_JAR" -H "$CRUMB" "$API_ROUTE/$i/api/json")
HTTP_CODE=$(tail -n1 <<< "$RES")
JSON=$(sed '$ d' <<< "$RES")
if [[ $HTTP_CODE == "200" ]]; then
STILL_RUNNING=$(echo $JSON | jq .inProgress)
STILL_RUNNING=$(echo "$JSON" | jq .inProgress)
if [[ $STILL_RUNNING == "true" ]]; then
echo -e "Build $i: ${YELLOW}still running${NC}"
continue
@@ -119,11 +119,11 @@ function _looper() {
echo -e "You are about to start $RUNS Jenkins builds against the $BRANCH branch."
echo -e "If you expect this to run overnight, ${UNDERLINE}${BOLD}unplug the cold reboot power switch${NC} from the testing closet before."
echo ""
read -p "Press (y/Y) to confirm: " choice
read -r -p "Press (y/Y) to confirm: " choice
if [[ "$choice" == "y" || "$choice" == "Y" ]]; then
loop
fi
}
_looper $@
_looper "$@"
+1 -1
View File
@@ -4,4 +4,4 @@ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
export FINGERPRINT="TOYOTA_COROLLA_TSS2"
export SKIP_FW_QUERY="1"
$DIR/../launch_openpilot.sh
"$DIR/../launch_openpilot.sh"
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env python3
import sys
import tomllib
import importlib.metadata
from pathlib import Path
def main() -> int:
if sys.prefix == sys.base_prefix:
print("Dependency checks require a virtual environment. Run tools/op.sh setup first.")
return 1
project = tomllib.loads((Path(__file__).resolve().parents[2] / "pyproject.toml").read_text())["project"]
direct = len(project["dependencies"]) + sum(len(deps) for deps in project["optional-dependencies"].values())
# Count each installed package once, including transitive dependencies and all extras.
packages = {dist.metadata["Name"].lower().replace("_", "-") for dist in importlib.metadata.distributions()}
# Logical file sizes avoid filesystem block-size differences. Don't follow links to the interpreter or source tree.
size = sum(path.stat().st_size for path in Path(sys.prefix).rglob("*") if not path.is_symlink() and path.is_file())
"""
This test prevents our depency footprint from growing.
These values are *not* intended to be increased, and we
expect to strictly drive these down over time.
"""
failed = False
for name, value, limit in (
("Direct dependencies (all extras)", direct, 39),
("Total dependencies", len(packages), 84),
("Venv size (MiB)", size / 1024**2, 570),
):
print(f"{name}: {value:g} (limit: {limit})")
failed |= value > limit
return int(failed)
if __name__ == "__main__":
raise SystemExit(main())
+2 -2
View File
@@ -2,9 +2,9 @@
FAIL=0
if grep -n '\(#\|//\)\([[:space:]]*\)NOMERGE' $@; then
if grep -n '\(#\|//\)\([[:space:]]*\)NOMERGE' "$@"; then
echo -e "NOMERGE comments found! Remove them before merging\n"
FAIL=1
fi
exit $FAIL
exit "$FAIL"
+3 -3
View File
@@ -2,14 +2,14 @@
FAIL=0
if grep '^#!.*python' $@ | grep -v '#!/usr/bin/env python3$'; then
if grep -I '^#!.*python' "$@" | grep -v '#!/usr/bin/env python3$'; then
echo -e "Invalid shebang! Must use '#!/usr/bin/env python3'\n"
FAIL=1
fi
if grep '^#!.*bash' $@ | grep -v '#!/usr/bin/env bash$'; then
if grep -I '^#!.*bash' "$@" | grep -v '#!/usr/bin/env bash$'; then
echo -e "Invalid shebang! Must use '#!/usr/bin/env bash'"
FAIL=1
fi
exit $FAIL
exit "$FAIL"
+132
View File
@@ -0,0 +1,132 @@
#!/usr/bin/env python3
"""A minimal shellcheck-like static analysis tool for shell scripts.
Covers syntax, unquoted expansions, scalar $@ assignments, and read -r.
"""
import re
import argparse
import subprocess
from pathlib import Path
VARIABLE = re.compile(r"\$(?:\{[^}\n]*\}|[A-Za-z_]\w*|[@*0-9])")
ASSIGNMENT = re.compile(r"[A-Za-z_]\w*(?:\[[^]]*\])?\+?=")
OPAQUE = re.compile(r"\$?\(\([^\n]*?\)\)|\[\[.*?\]\]", re.DOTALL)
HEREDOC = re.compile(r"<<(-?)\s*('[^']+'|\"[^\"]+\"|\\?[A-Za-z_]\w*)")
def commands(text):
def scan(i=0, end="", pattern_group=False):
start, quote, words, expansions, documents = i, False, [], [], []
cases = []
while i < len(text):
c = text[i]
if c == "\\":
i += 2
continue
if c == "'" and not quote:
i = text.find("'", i + 1) + 1 or len(text)
continue
if c == '"':
quote = not quote
elif (not quote or text.startswith("$((", i)) and (match := OPAQUE.match(text, i)):
i = match.end()
continue
elif text.startswith("$(", i):
if not quote:
expansions.append(i)
i = yield from scan(i + 2, ")")
continue
elif match := VARIABLE.match(text, i):
if not quote and not match[0].startswith("${#"):
expansions.append(i)
i = match.end()
continue
elif not quote:
if text.startswith("<<<", i):
i += 3
continue
if c == "#" and i == start:
i = text.find("\n", i)
i = len(text) if i < 0 else i
start = i
continue
if not text.startswith("<<<", i) and (match := HEREDOC.match(text, i)):
documents.append((match[2].strip("'\"").lstrip("\\"), bool(match[1])))
i = match.end()
continue
if c in " \t\r\n;|&()":
if start < i:
words.append((text[start:i], start, expansions))
if len(words) >= 3 and words[0][0] == "case" and words[-1][0] == "in":
cases.append(True)
words = []
if words and words[0][0] == "esac" and cases:
cases.pop()
words = []
pattern = bool(cases and cases[-1])
expansions = []
if c in "\n;|&()":
if words and not (pattern or pattern_group) and (c != ")" or end):
yield words
words = []
if c == end and not pattern:
return i + 1
if c == ")" and pattern:
cases[-1] = False
if cases and (terminator := re.match(r";(?:;&|;|&)", text[i:])):
cases[-1] = True
i += len(terminator[0]) - 1
if c == "(":
if pattern and i == start:
cases[-1] = False
i = yield from scan(i + 1, ")", pattern or pattern_group)
start = i
continue
if c == "\n":
for delimiter, strip_tabs in documents:
while i < len(text):
stop = text.find("\n", i + 1)
stop = len(text) if stop < 0 else stop
line, i = text[i + 1:stop], stop
if (line.lstrip("\t") if strip_tabs else line) == delimiter:
break
documents = []
start = i + 1
i += 1
if start < i:
words.append((text[start:i], start, expansions))
if words:
yield words
return i
yield from scan()
def check_text(text):
for words in commands(text):
command = next((w for w, _, _ in words if not ASSIGNMENT.match(w) and w not in {"if", "then", "elif", "while", "until", "do", "!"}), "")
prefix = True
for index, (word, start, expansions) in enumerate(words):
assignment = ASSIGNMENT.match(word) and (prefix or command in {"export", "local", "declare", "readonly", "typeset"})
prefix = prefix and (bool(assignment) or word in {"if", "then", "elif", "while", "until", "do", "!"})
for offset in expansions:
array = word in {"$@", "$*"} or "[@]" in word or "[*]" in word
if not assignment and (command not in {"case", "for", "select"} or array) and not (index and words[index - 1][0] == "<<<"):
yield text.count("\n", 0, offset) + 1, "Quote this expansion to prevent word splitting and globbing"
if assignment and re.fullmatch(r'"[^"\n]*\$@[^"\n]*"', ASSIGNMENT.sub("", word, count=1)):
yield text.count("\n", 0, start) + 1, 'Use an array for "$@", or "$*" to join arguments'
if command == "read" and not any(re.fullmatch(r"-[A-Za-z]*r[A-Za-z0-9]*", w) for w, _, _ in words):
yield text.count("\n", 0, next(start for w, start, _ in words if w == "read")) + 1, "Use read -r to preserve backslashes"
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("filenames", nargs="+")
failed = False
for filename in parser.parse_args().filenames:
syntax = subprocess.run(["bash", "-n", "--", filename], check=False)
failed |= syntax.returncode != 0
if syntax.returncode == 0:
for line, message in check_text(Path(filename).read_text()):
print(f"{filename}:{line}: {message}")
failed = True
raise SystemExit(failed)
+37 -24
View File
@@ -9,7 +9,7 @@ NC='\033[0m'
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
ROOT="$DIR/../../"
cd $ROOT
cd "$ROOT"
FAILED=0
@@ -26,10 +26,10 @@ function run() {
done
shift 1;
CMD="$@"
CMD=("$@")
set +e
log="$((eval "$CMD" ) 2>&1)"
log="$("${CMD[@]}" 2>&1)"
if [[ $? -eq 0 ]]; then
echo -e "[${GREEN}✔${NC}]"
@@ -42,22 +42,21 @@ function run() {
}
function run_tests() {
ALL_FILES=$1
PYTHON_FILES=$2
run "ruff" ruff check openpilot --quiet
run "check_indentation" $DIR/check_indentation.py $PYTHON_FILES
run "check_added_large_files" $DIR/check_added_large_files.py --maxkb=120 $ALL_FILES
run "check_shebang_scripts_are_executable" $DIR/check_shebang_scripts_are_executable.py $ALL_FILES
run "check_shebang_format" $DIR/check_shebang_format.sh $ALL_FILES
run "check_nomerge_comments" $DIR/check_nomerge_comments.sh $ALL_FILES
run "check_shell" python3 "$DIR/check_shell.py" "${SHELL_FILES[@]}"
run "check_dependencies" python3 "$DIR/check_dependencies.py"
run "check_indentation" "$DIR/check_indentation.py" "${PYTHON_FILES[@]}"
run "check_added_large_files" "$DIR/check_added_large_files.py" --maxkb=120 "${ALL_FILES[@]}"
run "check_shebang_scripts_are_executable" "$DIR/check_shebang_scripts_are_executable.py" "${ALL_FILES[@]}"
run "check_shebang_format" "$DIR/check_shebang_format.sh" "${ALL_FILES[@]}"
run "check_nomerge_comments" "$DIR/check_nomerge_comments.sh" "${ALL_FILES[@]}"
if [[ -z "$FAST" ]]; then
run "ty" ty check openpilot
run "codespell" codespell $ALL_FILES --ignore-words=$ROOT/.codespellignore
run "codespell" codespell "${ALL_FILES[@]}" --ignore-words="$ROOT/.codespellignore"
fi
return $FAILED
return "$FAILED"
}
function help() {
@@ -67,6 +66,8 @@ function help() {
echo ""
echo -e "${BOLD}${UNDERLINE}Tests:${NC}"
echo -e " ${BOLD}ruff${NC}"
echo -e " ${BOLD}check_shell${NC}"
echo -e " ${BOLD}check_dependencies${NC}"
echo -e " ${BOLD}check_indentation${NC}"
echo -e " ${BOLD}ty${NC}"
echo -e " ${BOLD}codespell${NC}"
@@ -101,17 +102,29 @@ while [[ $# -gt 0 ]]; do
esac
done
RUN=$([ -z "$RUN" ] && echo "" || echo "!($(echo $RUN | sed 's/ /|/g'))")
SKIP="@($(echo $SKIP | sed 's/ /|/g'))"
RUN=$([ -z "$RUN" ] && echo "" || echo "!($(echo "$RUN" | sed 's/ /|/g'))")
SKIP="@($(echo "$SKIP" | sed 's/ /|/g'))"
IGNORED_DIRS="^openpilot/third_party/.*"
GIT_FILES="$(git ls-files openpilot | grep -vE "$IGNORED_DIRS")"
ALL_FILES=""
for f in $GIT_FILES; do
if [[ -f $f ]]; then
ALL_FILES+="$f"$'\n'
ALL_FILES=()
PYTHON_FILES=()
while IFS= read -r -d '' f; do
if [[ $f =~ ^openpilot/third_party/.* ]]; then
continue
fi
done
PYTHON_FILES=$(echo "$ALL_FILES" | grep --color=never '.py$' || true)
if [[ -f $f ]]; then
ALL_FILES+=("$f")
if [[ $f == *.py ]]; then
PYTHON_FILES+=("$f")
fi
fi
done < <(git ls-files -z openpilot)
run_tests "$ALL_FILES" "$PYTHON_FILES"
# Include tooling, launchers, and the extensionless Git hook.
SHELL_FILES=()
while IFS= read -r -d '' f; do
if [[ -f $f ]]; then
SHELL_FILES+=("$f")
fi
done < <(git ls-files -z '*.sh' '*.bash' scripts/post-commit)
run_tests
+2 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
function fail {
echo $1 >&2
echo "$1" >&2
exit 1
}
@@ -14,7 +14,7 @@ function retry {
"$@" && break || {
if [[ $n -lt $max ]]; then
((n++))
sleep $delay;
sleep "$delay";
else
fail "The command has failed after $n attempts."
fi