[robotpy] Build examples (#8629)

This hooks up the bazel build to the robotpyExamples. It can use the
(formly pyfrc or whatever) automatic unit tests for an example, as well
as exposing the ability to run the example in simulation, with or
without `halsim_gui` with a command such as `bazel run
//robotpyExamples:AddressableLED-sim`

This required building and using wheels instead of just a normal
`py_library`, so that things like `ENTRY_POINTS` can be used. I took a
bare bones approach to building and naming the wheels (for example the
native ones don't have the OS info or python version in them, so they
wouldn't be suitable publish to pypi, but that can always be updated
later.
This commit is contained in:
PJ Reiniger
2026-03-06 02:18:37 -05:00
committed by GitHub
parent 26b2b08c8d
commit 51a3876330
37 changed files with 498 additions and 25 deletions

View File

@@ -0,0 +1,46 @@
load("@allwpilib_pip_deps//:requirements.bzl", "requirement")
load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_file")
load("@rules_python//python:defs.bzl", "py_binary")
load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
load(":define_examples.bzl", "define_examples")
py_binary(
name = "generate_bazel_files",
srcs = ["generate_bazel_files.py"],
target_compatible_with = select({
"@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@platforms//:incompatible"],
"@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"],
"//conditions:default": [],
}),
deps = [
requirement("tomli"),
],
)
cmd = "$(locations :generate_bazel_files) $(OUTS)"
genrule(
name = "generate_bazel_files_rule",
srcs = [
"examples.toml",
],
outs = ["gen/example_projects.bzl"],
cmd = cmd,
tools = [":generate_bazel_files"],
)
write_source_file(
name = "write_example_project_list",
in_file = ":generate_bazel_files_rule",
out_file = "example_projects.bzl",
suggested_update_target = "//:write_all",
tags = ["pregeneration"],
visibility = ["//visibility:public"],
)
py_console_script_binary(
name = "robotpy",
pkg = "@allwpilib_pip_deps//robotpy_cli",
)
define_examples()

View File

@@ -0,0 +1,44 @@
load("@allwpilib_pip_deps//:requirements.bzl", "requirement")
load("@rules_python//python:defs.bzl", "py_binary", "py_test")
load("//robotpyExamples:example_projects.bzl", "PROJECTS")
def define_examples():
for example_folder in PROJECTS:
base_name = example_folder.replace("/", "_")
common_kwargs = dict(
srcs = [":robotpy_entry_point.py"],
main = "robotpy_entry_point.py",
data = native.glob([example_folder + "/**"]),
imports = [example_folder],
)
common_deps = [
":robotpy",
"//apriltag:robotpy-apriltag",
"//commandsv2:commandsv2-py",
"//wpilibc:robotpy-wpilib",
"//romiVendordep:robotpy-romi",
"//xrpVendordep:robotpy-xrp",
requirement("numpy"),
]
py_test(
name = base_name + "-test",
args = ["--main", "$(location " + example_folder + "/robot.py)", "test", "--builtin"],
deps = common_deps,
size = "small",
**common_kwargs
)
py_binary(
name = base_name + "-run",
args = ["--main", "$(location " + example_folder + "/robot.py)", "run"],
deps = common_deps,
**common_kwargs
)
py_binary(
name = base_name + "-sim",
args = ["--main", "$(location " + example_folder + "/robot.py)", "sim"],
deps = common_deps + ["//simulation/halsim_gui:robotpy-halsim-gui"],
**common_kwargs
)

View File

@@ -0,0 +1,54 @@
PROJECTS = [
"AddressableLED",
"AprilTagsVision",
"ArcadeDrive",
"ArcadeDriveXboxController",
"ArmSimulation",
"CANPDP",
"DifferentialDriveBot",
"DifferentialDrivePoseEstimator",
"DigitalCommunication",
"DriveDistanceOffboard",
"DutyCycleEncoder",
"DutyCycleInput",
"ElevatorExponentialProfile",
"ElevatorExponentialSimulation",
"ElevatorProfiledPID",
"ElevatorSimulation",
"ElevatorTrapezoidProfile",
"Encoder",
"EventLoop",
"FlywheelBangBangController",
"GettingStarted",
"Gyro",
"GyroMecanum",
"HatchbotInlined",
"HatchbotTraditional",
"HidRumble",
"HttpCamera",
"I2CCommunication",
"IntermediateVision",
"MecanumBot",
"MecanumDrive",
"MecanumDrivePoseEstimator",
"Mechanism2d",
"MotorControl",
"PotentiometerPID",
"QuickVision",
"RapidReactCommandBot",
"RomiReference",
"SelectCommand",
"SimpleDifferentialDriveSimulation",
"Solenoid",
"StateSpaceArm",
"StateSpaceElevator",
"StateSpaceFlywheel",
"StateSpaceFlywheelSysId",
"SwerveBot",
"SwerveDrivePoseEstimator",
"SysId",
"TankDrive",
"TankDriveXboxController",
"UnitTest",
"XrpReference",
]

View File

@@ -0,0 +1,25 @@
import sys
import tomli
def main():
toml_filename = "robotpyExamples/examples.toml"
output_file = "robotpyExamples/example_projects.bzl"
with open(toml_filename, "rb") as f:
data = tomli.load(f)
contents = "PROJECTS = [\n"
for test_folder in data["tests"]["base"]:
contents += f' "{test_folder}",\n'
contents += "]\n"
if len(sys.argv) == 2:
output_file = sys.argv[1]
with open(output_file, "w") as f:
f.write(contents)
if __name__ == "__main__":
main()