circuitpython/tools/ci_fetch_deps.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

236 lines
6.9 KiB
Python
Raw Normal View History

import os
import sys
import time
import shlex
import pathlib
import re
import subprocess
TOP = pathlib.Path(__file__).parent.parent
def _git_version():
version_str = subprocess.check_output(["git", "--version"], encoding="ascii", errors="replace")
version_str = re.search("([0-9]\.*)*[0-9]", version_str).group(0)
return tuple(int(part) for part in version_str.split("."))
clone_supports_filter = (
False if "NO_USE_CLONE_FILTER" in os.environ else _git_version() >= (2, 36, 0)
)
if clone_supports_filter:
filter_maybe = "--filter=blob:none"
else:
filter_maybe = ""
def _all_submodules():
submodule_str = subprocess.check_output(
["git", "submodule", "status"], encoding="ascii", errors="replace", cwd=TOP
)
return [row.split()[1] for row in submodule_str.strip().split("\n")]
all_submodules = _all_submodules()
def matching_submodules(s):
if s.endswith("/"):
return [m for m in all_submodules if m.startswith(s)]
elif s not in all_submodules:
raise ValueError(f"{s!r} is not a submodule")
return [s]
# Submodules needed by port builds outside of their ports directory.
# Should we try and detect these?
PORT_DEPS = {
"atmel-samd": [
"extmod/ulab/",
"lib/adafruit_floppy/",
"lib/mp3/",
"lib/protomatter/",
"lib/quirc/",
"lib/tinyusb/",
2023-11-11 19:02:05 -05:00
"lib/tlsf",
"data/nvm.toml/",
],
2023-11-11 19:02:05 -05:00
"broadcom": ["extmod/ulab/", "lib/tlsf", "lib/tinyusb/"],
"cxd56": ["extmod/ulab/", "lib/tlsf", "lib/tinyusb/"],
2022-10-05 17:17:58 -04:00
"espressif": [
"extmod/ulab/",
2023-09-06 16:22:42 -04:00
"lib/certificates/",
2022-10-05 17:17:58 -04:00
"lib/protomatter/",
"lib/quirc/",
2023-11-11 19:02:05 -05:00
"lib/tlsf",
2022-10-05 17:17:58 -04:00
"lib/tinyusb/",
],
2023-11-11 19:02:05 -05:00
"litex": ["extmod/ulab/", "lib/tinyusb/", "lib/tlsf"],
"mimxrt10xx": ["extmod/ulab/", "lib/tinyusb/", "lib/tlsf", "data/nvm.toml/"],
"nrf": [
"extmod/ulab/",
"lib/mp3/",
"lib/protomatter/",
"lib/tinyusb/",
"lib/tlsf",
"data/nvm.toml/",
],
"raspberrypi": [
"extmod/ulab/",
"lib/adafruit_floppy/",
"lib/mbedtls/",
"lib/mp3/",
2023-09-06 16:22:42 -04:00
"lib/certificates/",
"lib/protomatter/",
"lib/quirc/",
"lib/tinyusb/",
2023-11-11 19:02:05 -05:00
"lib/tlsf",
"data/nvm.toml/",
],
2023-11-11 19:02:05 -05:00
"silabs": ["extmod/ulab/", "data/nvm.toml/", "lib/tlsf"],
"stm": [
"extmod/ulab/",
"lib/mp3/",
"lib/protomatter/",
"lib/tinyusb/",
"lib/tlsf",
"data/nvm.toml/",
]
# omit unix which is part of the "test" target below
}
def run(title, command, cwd):
print("::group::" + title, flush=True)
print(f"{command} (in {cwd})", flush=True)
start = time.monotonic()
try:
subprocess.run(shlex.split(command), stderr=subprocess.STDOUT, check=True, cwd=cwd)
finally:
print("::endgroup::", flush=True)
print("Duration:", time.monotonic() - start, flush=True)
def matching_submodules(where):
for m in all_submodules:
if m in where:
yield m
for w in where:
if m.startswith(f"{w}/"):
yield m
break
def fetch(where):
if clone_supports_filter:
run(
"Init submodules (using filter)",
f"git submodule update --init {filter_maybe} {' '.join(where)}",
cwd=TOP,
)
else:
run(
"Init submodules (using depth)",
f"git submodule update --init --depth 1 {' '.join(where)}",
cwd=TOP,
)
for s in matching_submodules([w for w in where if w.startswith("frozen")]):
run(f"Ensure tags exist in {s}", "git fetch --tags --depth 1", cwd=TOP / s)
def set_output(name, value):
if "GITHUB_OUTPUT" in os.environ:
with open(os.environ["GITHUB_OUTPUT"], "at") as f:
print(f"{name}={value}", file=f)
else:
print(f"{name}: {value!r}")
SUBMODULES_BY_TARGET = {}
def main(target):
submodules = []
print("Target:", target)
if target == "all":
submodules = [".", "frozen"] # explicitly list frozen to get tags
elif target == "scheduler":
2023-02-10 09:17:51 -05:00
submodules = ["extmod/ulab", "lib/", "tools/"]
elif target == "tests":
submodules = [
"extmod/ulab",
"lib/",
"tools/",
"frozen/Adafruit_CircuitPython_asyncio",
"frozen/Adafruit_CircuitPython_Ticks",
]
elif target == "docs":
# used in .readthedocs.yml to generate RTD
submodules = ["extmod/ulab", "frozen"]
elif target == "mpy-cross" or target == "mpy-cross-mac":
submodules = ["tools/"] # for huffman
elif target == "windows":
# This builds one board from a number of ports so fill out a bunch of submodules
2023-04-19 18:42:02 -04:00
for port in ("atmel-samd", "nrf", "raspberrypi", "stm"):
2023-04-19 19:02:01 -04:00
submodules.append(f"ports/{port}")
2023-04-19 18:42:02 -04:00
submodules.extend(PORT_DEPS[port])
unique_submodules = set(submodules)
submodules = list(unique_submodules)
elif target == "website":
submodules = ["tools/adabot", "frozen"]
elif target == "pre-commit":
2023-01-20 23:54:08 -05:00
submodules = ["extmod/ulab"]
elif target in PORT_DEPS:
submodules = ["data", "extmod", "lib", "tools", "frozen", f"ports/{target}"] + PORT_DEPS[
target
]
else:
p = list(pathlib.Path(TOP).glob(f"ports/*/boards/{target}/mpconfigboard.mk"))
if not p:
raise RuntimeError(f"Unsupported target: {target}")
config = p[0]
# Add the ports folder to init submodules
port_folder = config.parents[2]
port = port_folder.name
submodules.append(f"ports/{port}")
submodules.append("tools/") # for huffman
submodules.extend(PORT_DEPS[port])
with config.open() as f:
for line in f.readlines():
prefix = "FROZEN_MPY_DIRS += $(TOP)/"
if line.startswith(prefix):
lib_folder = line.strip()[len(prefix) :]
# Drop everything after the second folder because the frozen
# folder may be inside the submodule.
if lib_folder.count("/") > 1:
lib_folder = lib_folder.split("/", maxsplit=2)
lib_folder = "/".join(lib_folder[:2])
submodules.append(lib_folder)
print("Submodules:", " ".join(submodules))
if submodules:
fetch(submodules)
for submodule in submodules:
if submodule.startswith("frozen"):
set_output("frozen_tags", True)
break
else:
set_output("frozen_tags", False)
if __name__ == "__main__":
if len(sys.argv) < 2:
raise SystemExit("Usage: ci_fetch_deps dep...")
run("Sync submodule URLs", "git submodule sync --quiet", cwd=TOP)
# Target will be a board, "test", "docs", "mpy-cross-mac", or "windows"
for target in sys.argv[1:]:
main(target)