rosotacom-dev 2.5.dev6__tar.gz → 2.5.dev8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/PKG-INFO +23 -1
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/README.md +22 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/cli.py +261 -30
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom_dev.egg-info/PKG-INFO +23 -1
- rosotacom_dev-2.5.dev8/src/rosotacom_dev.egg-info/scm_version.json +8 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_cli.py +164 -1
- rosotacom_dev-2.5.dev6/src/rosotacom_dev.egg-info/scm_version.json +0 -8
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.devcontainer/devcontainer.json.template +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.devcontainer/re_generate_devcontainer_json.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/CODEOWNERS +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/dependabot.yml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/workflows/benchmark-calibrate.yml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/workflows/benchmark-gate.yml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/workflows/dev-release.yml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/workflows/image-scan.yml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/workflows/nightly-e2e.yml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/workflows/pr-lightweight.yml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/workflows/pr-merge-gate.yml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.github/workflows/release.yml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/.pre-commit-config.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/AGENTS.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/CONCURRENCY.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/CONTRIBUTING.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/DEVELOPMENT_PRINCIPLES.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/MANIFEST.in +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/budgets.jsonl +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/calibration/README.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/calibration/capacity-size-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/calibration/probe-loss-nominal-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/calibration/probe-loss-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/calibration/probe-loss-tight-fastdds.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/calibration/probe-loss-tight-zenoh.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/codecov.yml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/deployment-configuration.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/benchmark-ab.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/benchmark-bag-as-load.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/ci.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/ffmpeg-keyframes.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/findings/README.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/findings/delay-alone-no-loss.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/findings/head-of-line-irregularity.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/findings/lighter-message-loss.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/forensics-report.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/geo-link-map.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/github-repository-settings.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/link-trace.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/owner-runbook.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/performance-bands.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/playbooks/README.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/quality-model.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/release-notes/TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/release-notes/v2.1.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/release-notes/v2.2.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/release-notes/v2.3.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/release-notes/v2.4.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/release.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/rfcs/0002-expectation-concepts.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/rfcs/0003-metric-backbone.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/rfcs/0004-network-profiles.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/rfcs/0006-dynamic-qos.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/rfcs/0007-regression-gate.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/rfcs/README.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/testing.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/docs/work-items.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/install.sh +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/justfile +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/media/control_center.png +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/media/echo_test.png +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/media/forensics-report-example.png +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/media/host.png +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/media/vehicle.png +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/pyproject.toml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/requirements.txt +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/run_session_in_container.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/session-configuration.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/__init__.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/__main__.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/anonymize.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/benched_set.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/benchmark.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/deployment.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/forensics.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/geomap.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/plots.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/py.typed +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/benched-set.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/.gitignore +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/README.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/__init__.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/profiles.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ros2docker.json.example +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/status_eval.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/transit.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom/video_quality.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom_dev.egg-info/SOURCES.txt +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom_dev.egg-info/requires.txt +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom_dev.egg-info/scm_file_list.json +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/stop_session_in_container.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/terminology.md +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/contract/test_benched_set_registry.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/contract/test_findings.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/contract/test_markdown_links.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/contract/test_ota_source_bundle.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/contract/test_package_metadata.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/contract/test_packaged_resources.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/contract/test_profile_covers_generated_commands.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/contract/test_pytest_policy.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/contract/test_readme_examples.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/contract/test_security_maintenance_config.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/contract/test_workflow_contracts.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/e2e/conftest.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/e2e/test_anonymize_e2e.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/e2e/test_benchmark_ab.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/e2e/test_benchmark_capacity.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/e2e/test_benchmark_replay.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/e2e/test_parallel_smoke.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/e2e/test_smoke.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/e2e/test_timeline_stepping.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/e2e/test_video_quality_e2e.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/sessions/generate_rmw_matrix.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_anonymize.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_benched_set.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_concurrency.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_deployment.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_forensics.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_geomap.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_link_trace.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_plots.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_status_eval.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_status_overview.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_transit.py +0 -0
- {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev8}/tests/unit/test_video_quality.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rosotacom-dev
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.dev8
|
|
4
4
|
Summary: Host CLI for ROS OTA communication sessions.
|
|
5
5
|
Author: develNor
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -460,6 +460,11 @@ rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
|
460
460
|
--install-mode pin # defaults to your own version
|
|
461
461
|
rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
462
462
|
--install-mode pin --install-pin 2.4
|
|
463
|
+
|
|
464
|
+
# test the machines as they are: no staging, no install, their own checkouts
|
|
465
|
+
rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
466
|
+
--peer-ssh b=robot-b --install-mode checkout \
|
|
467
|
+
--peer-checkout a=/home/me/fleet_mgmt --peer-checkout b=/home/robot/fleet_mgmt
|
|
463
468
|
```
|
|
464
469
|
|
|
465
470
|
`source` is right while iterating on rosotacom itself — the peers run the code
|
|
@@ -469,6 +474,23 @@ missing from the wheel, an undeclared dependency) fails in the rehearsal instead
|
|
|
469
474
|
of on the target machine. `source` cannot catch that class of defect by
|
|
470
475
|
construction, because it never builds the artefact that ships.
|
|
471
476
|
|
|
477
|
+
`checkout` answers a different question again: not "does this artefact work" but
|
|
478
|
+
"is *this machine* ready". Nothing is staged and nothing is installed — each
|
|
479
|
+
peer runs the rosotacom it already has, from the project checkout it already
|
|
480
|
+
has, so what is under test is the state git and the machine's own install left
|
|
481
|
+
behind, dependency pins included. Ground truth moves into the repository: push,
|
|
482
|
+
pull, run. It is also the only mode in which a project may reference anything
|
|
483
|
+
outside its own directory — staging copies the project directory, so a mount or
|
|
484
|
+
config path leading above it cannot survive the copy and fails on the peer as a
|
|
485
|
+
missing path.
|
|
486
|
+
|
|
487
|
+
Because the same repository sits at a different absolute path on every machine,
|
|
488
|
+
`--peer-checkout` is required for every peer; the path *inside* the repository
|
|
489
|
+
is taken from your own checkout, so the project has to live in one. Preparation
|
|
490
|
+
becomes verification: each peer is asked whether the checkout, the project file
|
|
491
|
+
and `rosotacom` are there, and each version is printed. `--cleanup` does nothing
|
|
492
|
+
in this mode — there is no staging to undo, and the workdir is your repository.
|
|
493
|
+
|
|
472
494
|
The run manifest records which mode and which version the peers ran, so a result
|
|
473
495
|
can be attributed to an artefact rather than to a working copy.
|
|
474
496
|
|
|
@@ -415,6 +415,11 @@ rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
|
415
415
|
--install-mode pin # defaults to your own version
|
|
416
416
|
rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
417
417
|
--install-mode pin --install-pin 2.4
|
|
418
|
+
|
|
419
|
+
# test the machines as they are: no staging, no install, their own checkouts
|
|
420
|
+
rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
421
|
+
--peer-ssh b=robot-b --install-mode checkout \
|
|
422
|
+
--peer-checkout a=/home/me/fleet_mgmt --peer-checkout b=/home/robot/fleet_mgmt
|
|
418
423
|
```
|
|
419
424
|
|
|
420
425
|
`source` is right while iterating on rosotacom itself — the peers run the code
|
|
@@ -424,6 +429,23 @@ missing from the wheel, an undeclared dependency) fails in the rehearsal instead
|
|
|
424
429
|
of on the target machine. `source` cannot catch that class of defect by
|
|
425
430
|
construction, because it never builds the artefact that ships.
|
|
426
431
|
|
|
432
|
+
`checkout` answers a different question again: not "does this artefact work" but
|
|
433
|
+
"is *this machine* ready". Nothing is staged and nothing is installed — each
|
|
434
|
+
peer runs the rosotacom it already has, from the project checkout it already
|
|
435
|
+
has, so what is under test is the state git and the machine's own install left
|
|
436
|
+
behind, dependency pins included. Ground truth moves into the repository: push,
|
|
437
|
+
pull, run. It is also the only mode in which a project may reference anything
|
|
438
|
+
outside its own directory — staging copies the project directory, so a mount or
|
|
439
|
+
config path leading above it cannot survive the copy and fails on the peer as a
|
|
440
|
+
missing path.
|
|
441
|
+
|
|
442
|
+
Because the same repository sits at a different absolute path on every machine,
|
|
443
|
+
`--peer-checkout` is required for every peer; the path *inside* the repository
|
|
444
|
+
is taken from your own checkout, so the project has to live in one. Preparation
|
|
445
|
+
becomes verification: each peer is asked whether the checkout, the project file
|
|
446
|
+
and `rosotacom` are there, and each version is printed. `--cleanup` does nothing
|
|
447
|
+
in this mode — there is no staging to undo, and the workdir is your repository.
|
|
448
|
+
|
|
427
449
|
The run manifest records which mode and which version the peers ran, so a result
|
|
428
450
|
can be attributed to an artefact rather than to a working copy.
|
|
429
451
|
|
|
@@ -125,9 +125,25 @@ OTA_SUDO_MODES = ("passwordless", "askpass")
|
|
|
125
125
|
# that ships, so a packaging defect — a file missing from the wheel, an
|
|
126
126
|
# undeclared dependency — fails here rather than on a Versuchsträger. `source`
|
|
127
127
|
# cannot catch that class of bug by construction.
|
|
128
|
-
|
|
128
|
+
#
|
|
129
|
+
# `checkout` is the third answer, and it inverts the question: nothing is
|
|
130
|
+
# staged and nothing is installed. Each peer runs the rosotacom it already has
|
|
131
|
+
# from the project checkout it already has, so what is under test is the state
|
|
132
|
+
# git put on that machine — including its dependency pins. `pin` still proves
|
|
133
|
+
# the artefact ships correctly; only `checkout` proves *this machine* is ready,
|
|
134
|
+
# which is what a deployment rehearsal actually asks. It is also the only mode
|
|
135
|
+
# in which a project may reference anything outside its own directory: staging
|
|
136
|
+
# copies the project directory, so a path leading above it cannot survive.
|
|
137
|
+
OTA_INSTALL_MODES = ("source", "pin", "checkout")
|
|
129
138
|
OTA_DEFAULT_SUDO_MODE = "passwordless"
|
|
130
139
|
|
|
140
|
+
# `ssh host 'cmd'` runs a non-login shell, so a pipx install in ~/.local/bin is
|
|
141
|
+
# not on PATH and the peer answers `rosotacom: command not found` — which reads
|
|
142
|
+
# as a broken machine rather than a missing PATH entry. The staged modes never
|
|
143
|
+
# meet this because they call an absolute path inside the workdir; checkout mode
|
|
144
|
+
# calls the peer's own command by name, so it has to say where that lives.
|
|
145
|
+
OTA_CHECKOUT_PATH_PREFIX = 'export PATH="$HOME/.local/bin:$PATH"; '
|
|
146
|
+
|
|
131
147
|
ws_creation_dir = WS_DIR / "session" / "creation"
|
|
132
148
|
session_gen_path = ws_creation_dir / "generate_session_files.py"
|
|
133
149
|
spec = importlib.util.spec_from_file_location("session_gen", session_gen_path)
|
|
@@ -212,6 +228,12 @@ class OtaSmokePeer:
|
|
|
212
228
|
name: str
|
|
213
229
|
ssh: str | None
|
|
214
230
|
address: str
|
|
231
|
+
#: Absolute path of this peer's project checkout, in `checkout` install mode
|
|
232
|
+
#: only. Per peer rather than one plan-wide value because the same
|
|
233
|
+
#: repository lives at a different absolute path on every machine — a
|
|
234
|
+
#: control centre runs it under a different account than a laptop does — and
|
|
235
|
+
#: a single workdir would silently be wrong on all but one of them.
|
|
236
|
+
checkout: str | None = None
|
|
215
237
|
|
|
216
238
|
|
|
217
239
|
@dataclass(frozen=True)
|
|
@@ -1001,6 +1023,10 @@ def _parse_peer_ssh_overrides(overrides: list[str] | None) -> dict[str, str]:
|
|
|
1001
1023
|
return parse_assignments(overrides, option="--peer-ssh")
|
|
1002
1024
|
|
|
1003
1025
|
|
|
1026
|
+
def _parse_peer_checkout_overrides(overrides: list[str] | None) -> dict[str, str]:
|
|
1027
|
+
return parse_assignments(overrides, option="--peer-checkout")
|
|
1028
|
+
|
|
1029
|
+
|
|
1004
1030
|
def _deployment_config(runtime: RuntimeConfig) -> DeploymentConfig | None:
|
|
1005
1031
|
return load_deployment(runtime.deployment)
|
|
1006
1032
|
|
|
@@ -1500,18 +1526,65 @@ def _ota_validate_install_mode(install_mode: str) -> str:
|
|
|
1500
1526
|
|
|
1501
1527
|
def _ota_rosotacom_path(install_mode: str) -> str:
|
|
1502
1528
|
"""Where the peer's rosotacom executable lands, relative to the workdir."""
|
|
1529
|
+
if install_mode == "checkout":
|
|
1530
|
+
# Not a path: the peer's own installation, whatever put it there. Naming
|
|
1531
|
+
# a path here would re-introduce the thing this mode removes — an
|
|
1532
|
+
# assumption by the orchestrator about the peer's file system.
|
|
1533
|
+
return "rosotacom"
|
|
1503
1534
|
return "venv/bin/rosotacom" if install_mode == "pin" else "source/.venv/bin/rosotacom"
|
|
1504
1535
|
|
|
1505
1536
|
|
|
1537
|
+
def _ota_checkout_project_path(project_config: Path) -> tuple[Path, str]:
|
|
1538
|
+
"""Split an active `rosotacom.yaml` into (checkout root, path inside it).
|
|
1539
|
+
|
|
1540
|
+
Checkout mode needs one repository-relative project path that is valid on
|
|
1541
|
+
every peer, and the honest source for it is the local checkout: walk up from
|
|
1542
|
+
the config until a `.git` entry appears. That is not a heuristic here — a
|
|
1543
|
+
mode whose ground truth is "what git put on the machine" is entitled to
|
|
1544
|
+
require that the project is in a repository, and requiring it makes the
|
|
1545
|
+
failure legible instead of producing a path that happens to be wrong on the
|
|
1546
|
+
other machine.
|
|
1547
|
+
"""
|
|
1548
|
+
config = project_config.resolve()
|
|
1549
|
+
for candidate in config.parents:
|
|
1550
|
+
if (candidate / ".git").exists():
|
|
1551
|
+
return candidate, config.relative_to(candidate).as_posix()
|
|
1552
|
+
raise RuntimeError(
|
|
1553
|
+
f"--install-mode checkout needs the project to live in a git checkout, and {config} is not in one. "
|
|
1554
|
+
"The peers resolve the project by its path inside the repository, so there has to be a repository."
|
|
1555
|
+
)
|
|
1556
|
+
|
|
1557
|
+
|
|
1506
1558
|
def _ota_plan_from_bindings(
|
|
1507
1559
|
bindings: dict[str, PeerBinding],
|
|
1508
1560
|
*,
|
|
1509
1561
|
workdir: str,
|
|
1510
1562
|
install_mode: str = "source",
|
|
1511
1563
|
install_pin: str | None = None,
|
|
1564
|
+
checkouts: Mapping[str, str] | None = None,
|
|
1565
|
+
project: str | None = None,
|
|
1512
1566
|
) -> OtaSmokePlan:
|
|
1513
|
-
_ota_validate_prepare_workdir(workdir)
|
|
1514
1567
|
_ota_validate_install_mode(install_mode)
|
|
1568
|
+
if install_mode == "checkout":
|
|
1569
|
+
if not checkouts or not project:
|
|
1570
|
+
raise RuntimeError("--install-mode checkout requires --peer-checkout for every peer.")
|
|
1571
|
+
missing = sorted(set(bindings) - set(checkouts))
|
|
1572
|
+
if missing:
|
|
1573
|
+
raise RuntimeError(
|
|
1574
|
+
"--install-mode checkout needs a checkout for every peer; missing: "
|
|
1575
|
+
+ ", ".join(f"--peer-checkout {name}=<path>" for name in missing)
|
|
1576
|
+
)
|
|
1577
|
+
unknown = sorted(set(checkouts) - set(bindings))
|
|
1578
|
+
if unknown:
|
|
1579
|
+
raise RuntimeError(f"--peer-checkout names a peer the session does not have: {', '.join(unknown)}")
|
|
1580
|
+
for name, path in sorted(checkouts.items()):
|
|
1581
|
+
if not path.startswith("/"):
|
|
1582
|
+
raise RuntimeError(f"--peer-checkout {name}={path}: a peer checkout must be an absolute path.")
|
|
1583
|
+
_ota_validate_prepare_workdir(path)
|
|
1584
|
+
else:
|
|
1585
|
+
_ota_validate_prepare_workdir(workdir)
|
|
1586
|
+
if checkouts:
|
|
1587
|
+
raise RuntimeError("--peer-checkout only applies to --install-mode checkout.")
|
|
1515
1588
|
if install_mode == "pin":
|
|
1516
1589
|
# Defaulting to the caller's own version makes `--install-mode pin`
|
|
1517
1590
|
# mean "rehearse what I am running, as it ships" without a second flag.
|
|
@@ -1524,13 +1597,19 @@ def _ota_plan_from_bindings(
|
|
|
1524
1597
|
elif install_pin is not None:
|
|
1525
1598
|
raise RuntimeError("--install-pin only applies to --install-mode pin.")
|
|
1526
1599
|
peers = {
|
|
1527
|
-
name: OtaSmokePeer(
|
|
1600
|
+
name: OtaSmokePeer(
|
|
1601
|
+
name=name,
|
|
1602
|
+
ssh=binding.ssh,
|
|
1603
|
+
address=binding.address,
|
|
1604
|
+
checkout=(checkouts or {}).get(name) if install_mode == "checkout" else None,
|
|
1605
|
+
)
|
|
1606
|
+
for name, binding in bindings.items()
|
|
1528
1607
|
}
|
|
1529
1608
|
return OtaSmokePlan(
|
|
1530
1609
|
state_path=None,
|
|
1531
1610
|
workdir=workdir,
|
|
1532
1611
|
rosotacom=_ota_rosotacom_path(install_mode),
|
|
1533
|
-
project="project/rosotacom.yaml",
|
|
1612
|
+
project=(project or "") if install_mode == "checkout" else "project/rosotacom.yaml",
|
|
1534
1613
|
peers=peers,
|
|
1535
1614
|
install_mode=install_mode,
|
|
1536
1615
|
install_pin=install_pin,
|
|
@@ -1540,13 +1619,16 @@ def _ota_plan_from_bindings(
|
|
|
1540
1619
|
def _ota_write_state(instance: SessionInstance, plan: OtaSmokePlan) -> OtaSmokePlan:
|
|
1541
1620
|
path = instance.host_dir / "ota-deployment.yaml"
|
|
1542
1621
|
payload = {
|
|
1543
|
-
"schema_version":
|
|
1622
|
+
"schema_version": 3,
|
|
1544
1623
|
"workdir": plan.workdir,
|
|
1545
1624
|
"rosotacom": plan.rosotacom,
|
|
1546
1625
|
"project": plan.project,
|
|
1547
1626
|
"install_mode": plan.install_mode,
|
|
1548
1627
|
"install_pin": plan.install_pin,
|
|
1549
|
-
"peers": {
|
|
1628
|
+
"peers": {
|
|
1629
|
+
name: {"address": peer.address, "ssh": peer.ssh, "checkout": peer.checkout}
|
|
1630
|
+
for name, peer in sorted(plan.peers.items())
|
|
1631
|
+
},
|
|
1550
1632
|
}
|
|
1551
1633
|
path.write_text(yaml.safe_dump(payload, sort_keys=False), encoding="utf-8")
|
|
1552
1634
|
return replace(plan, state_path=path)
|
|
@@ -1555,7 +1637,7 @@ def _ota_write_state(instance: SessionInstance, plan: OtaSmokePlan) -> OtaSmokeP
|
|
|
1555
1637
|
def _ota_load_state(path_arg: str) -> OtaSmokePlan:
|
|
1556
1638
|
path = Path(path_arg).expanduser().resolve()
|
|
1557
1639
|
raw = _load_yaml_file(path)
|
|
1558
|
-
if raw.get("schema_version") !=
|
|
1640
|
+
if raw.get("schema_version") != 3:
|
|
1559
1641
|
raise RuntimeError(f"Unsupported OTA deployment state: {path}")
|
|
1560
1642
|
peers_raw = raw.get("peers")
|
|
1561
1643
|
if not isinstance(peers_raw, dict) or len(peers_raw) != 2:
|
|
@@ -1568,6 +1650,7 @@ def _ota_load_state(path_arg: str) -> OtaSmokePlan:
|
|
|
1568
1650
|
name=str(name),
|
|
1569
1651
|
address=str(peer_raw["address"]),
|
|
1570
1652
|
ssh=str(peer_raw["ssh"]) if peer_raw.get("ssh") else None,
|
|
1653
|
+
checkout=str(peer_raw["checkout"]) if peer_raw.get("checkout") else None,
|
|
1571
1654
|
)
|
|
1572
1655
|
install_pin = raw.get("install_pin")
|
|
1573
1656
|
return OtaSmokePlan(
|
|
@@ -1680,9 +1763,15 @@ def _ota_project_cli_args(plan: OtaSmokePlan) -> list[str]:
|
|
|
1680
1763
|
return ["--rosotacom-config", plan.project]
|
|
1681
1764
|
|
|
1682
1765
|
|
|
1683
|
-
def
|
|
1766
|
+
def _ota_peer_workdir(plan: OtaSmokePlan, peer: OtaSmokePeer) -> str:
|
|
1767
|
+
"""The directory a peer's commands run in: its checkout, or the staging dir."""
|
|
1768
|
+
return peer.checkout or plan.workdir
|
|
1769
|
+
|
|
1770
|
+
|
|
1771
|
+
def _ota_rosotacom_command(plan: OtaSmokePlan, parts: list[str], peer: OtaSmokePeer) -> str:
|
|
1684
1772
|
command = [plan.rosotacom, *parts, *_ota_project_cli_args(plan)]
|
|
1685
|
-
|
|
1773
|
+
prefix = OTA_CHECKOUT_PATH_PREFIX if plan.install_mode == "checkout" else ""
|
|
1774
|
+
return f"{prefix}cd {shlex.quote(_ota_peer_workdir(plan, peer))} && {_ota_quote_cmd(command)}"
|
|
1686
1775
|
|
|
1687
1776
|
|
|
1688
1777
|
def _ota_source_checkout() -> Path | None:
|
|
@@ -2230,6 +2319,30 @@ def _infer_active_ota_smoke_run(
|
|
|
2230
2319
|
)
|
|
2231
2320
|
|
|
2232
2321
|
|
|
2322
|
+
def _ota_latest_state_for(
|
|
2323
|
+
runtime: RuntimeConfig, target: InteractiveSmokeTarget, instance_id: str | None
|
|
2324
|
+
) -> str | None:
|
|
2325
|
+
"""The newest `ota-deployment.yaml` for this target, if one is on disk.
|
|
2326
|
+
|
|
2327
|
+
Instances are laid out `<instances>/<date>/<session>_<time>_<instance-id>/`,
|
|
2328
|
+
so a named instance can be matched by suffix and an unnamed one by
|
|
2329
|
+
modification time. Returns None rather than raising: not finding a state is
|
|
2330
|
+
a normal outcome (nothing was ever started here), and the caller has a
|
|
2331
|
+
command line to fall back to.
|
|
2332
|
+
"""
|
|
2333
|
+
root = _session_instances_root(runtime)
|
|
2334
|
+
if not root.is_dir():
|
|
2335
|
+
return None
|
|
2336
|
+
candidates = sorted(
|
|
2337
|
+
(path for path in root.glob("*/*/ota-deployment.yaml")),
|
|
2338
|
+
key=lambda path: path.stat().st_mtime,
|
|
2339
|
+
reverse=True,
|
|
2340
|
+
)
|
|
2341
|
+
if instance_id:
|
|
2342
|
+
candidates = [path for path in candidates if path.parent.name.endswith(f"_{instance_id}")]
|
|
2343
|
+
return str(candidates[0]) if candidates else None
|
|
2344
|
+
|
|
2345
|
+
|
|
2233
2346
|
def _resolve_ota_smoke_context(
|
|
2234
2347
|
args: argparse.Namespace,
|
|
2235
2348
|
) -> tuple[RuntimeConfig, OtaSmokePlan, InteractiveSmokeTarget]:
|
|
@@ -2238,6 +2351,21 @@ def _resolve_ota_smoke_context(
|
|
|
2238
2351
|
getattr(args, "target", None), runtime, getattr(args, "target_type", "auto")
|
|
2239
2352
|
)
|
|
2240
2353
|
state_file = getattr(args, "state_file", None)
|
|
2354
|
+
if not state_file and getattr(args, "stop", False):
|
|
2355
|
+
# Stopping has to reach the run that exists, and the only record of how
|
|
2356
|
+
# that run was deployed is the state a start wrote. Reconstructing a
|
|
2357
|
+
# plan from the command line instead means guessing the install mode,
|
|
2358
|
+
# and the default guess is `source` — which points the stop at
|
|
2359
|
+
# `/tmp/rosotacom_ota/source/.venv/bin/rosotacom` for peers that were
|
|
2360
|
+
# started from their own checkouts. Observed on 2026-08-11: every peer
|
|
2361
|
+
# stop failed silently (they are best-effort), the containers stayed up,
|
|
2362
|
+
# and the only visible action was a cleanup removing a staging directory
|
|
2363
|
+
# that had never been created. Usually the live tmux session carries the
|
|
2364
|
+
# state path; when it does not — a killed session, a run started from
|
|
2365
|
+
# another terminal — the instance directory still does.
|
|
2366
|
+
state_file = _ota_latest_state_for(runtime, target, getattr(args, "instance_id", None))
|
|
2367
|
+
if state_file:
|
|
2368
|
+
print(f"OTA smoke: stopping the run recorded in {state_file}")
|
|
2241
2369
|
if state_file:
|
|
2242
2370
|
plan = _ota_load_state(state_file)
|
|
2243
2371
|
else:
|
|
@@ -2248,11 +2376,27 @@ def _resolve_ota_smoke_context(
|
|
|
2248
2376
|
peer_address=getattr(args, "peer_address", None),
|
|
2249
2377
|
peer_ssh=getattr(args, "peer_ssh", None),
|
|
2250
2378
|
)
|
|
2379
|
+
install_mode = str(getattr(args, "install_mode", None) or "source")
|
|
2380
|
+
checkouts = _parse_peer_checkout_overrides(getattr(args, "peer_checkout", None))
|
|
2381
|
+
project: str | None = None
|
|
2382
|
+
if install_mode == "checkout":
|
|
2383
|
+
if not runtime.rosotacom_config:
|
|
2384
|
+
raise RuntimeError("--install-mode checkout requires an active rosotacom.yaml project.")
|
|
2385
|
+
local_checkout, project = _ota_checkout_project_path(runtime.rosotacom_config)
|
|
2386
|
+
for name, path in sorted(checkouts.items()):
|
|
2387
|
+
binding = bindings.get(name)
|
|
2388
|
+
if binding is not None and not binding.ssh and Path(path).resolve() != local_checkout:
|
|
2389
|
+
raise RuntimeError(
|
|
2390
|
+
f"--peer-checkout {name}={path} names the peer that runs on this machine, but the active "
|
|
2391
|
+
f"project lives in {local_checkout}. Point it there, or give that peer an SSH target."
|
|
2392
|
+
)
|
|
2251
2393
|
plan = _ota_plan_from_bindings(
|
|
2252
2394
|
bindings,
|
|
2253
2395
|
workdir=str(getattr(args, "workdir", None) or "/tmp/rosotacom_ota"),
|
|
2254
|
-
install_mode=
|
|
2396
|
+
install_mode=install_mode,
|
|
2255
2397
|
install_pin=getattr(args, "install_pin", None),
|
|
2398
|
+
checkouts=checkouts,
|
|
2399
|
+
project=project,
|
|
2256
2400
|
)
|
|
2257
2401
|
plan_peers = set(plan.peers)
|
|
2258
2402
|
target_peers = set(_peer_keys_from_cfg(target.cfg))
|
|
@@ -2643,10 +2787,62 @@ def _ota_remote_package_dir(peer: OtaSmokePeer, plan: OtaSmokePlan, *, dry_run:
|
|
|
2643
2787
|
return located
|
|
2644
2788
|
|
|
2645
2789
|
|
|
2790
|
+
def _ota_verify_checkouts(plan: OtaSmokePlan, *, dry_run: bool) -> None:
|
|
2791
|
+
"""Checkout mode's replacement for staging: assert, do not install.
|
|
2792
|
+
|
|
2793
|
+
Nothing is copied and nothing is installed, so the only thing that can go
|
|
2794
|
+
wrong is a peer that is not in the state the caller thinks it is in — an
|
|
2795
|
+
unsynced checkout, a rosotacom that never got installed, a project path that
|
|
2796
|
+
exists on the laptop and not on the other machine. Each of those has a
|
|
2797
|
+
distinct one-line failure here, before any container starts, rather than a
|
|
2798
|
+
confusing one an hour later.
|
|
2799
|
+
"""
|
|
2800
|
+
for peer in plan.peers.values():
|
|
2801
|
+
checkout = shlex.quote(_ota_peer_workdir(plan, peer))
|
|
2802
|
+
project = shlex.quote(plan.project)
|
|
2803
|
+
_ota_run(
|
|
2804
|
+
peer,
|
|
2805
|
+
f"test -d {checkout}",
|
|
2806
|
+
label=f"{peer.name}: project checkout {_ota_peer_workdir(plan, peer)}",
|
|
2807
|
+
dry_run=dry_run,
|
|
2808
|
+
batch=True,
|
|
2809
|
+
)
|
|
2810
|
+
_ota_run(
|
|
2811
|
+
peer,
|
|
2812
|
+
f"test -f {checkout}/{project}",
|
|
2813
|
+
label=f"{peer.name}: project config {plan.project} inside the checkout",
|
|
2814
|
+
dry_run=dry_run,
|
|
2815
|
+
batch=True,
|
|
2816
|
+
)
|
|
2817
|
+
_ota_run(
|
|
2818
|
+
peer,
|
|
2819
|
+
f"{OTA_CHECKOUT_PATH_PREFIX}command -v rosotacom >/dev/null 2>&1",
|
|
2820
|
+
label=f"{peer.name}: rosotacom installed",
|
|
2821
|
+
dry_run=dry_run,
|
|
2822
|
+
batch=True,
|
|
2823
|
+
)
|
|
2824
|
+
version = _ota_run(
|
|
2825
|
+
peer,
|
|
2826
|
+
f"{OTA_CHECKOUT_PATH_PREFIX}rosotacom --version",
|
|
2827
|
+
label=f"{peer.name}: rosotacom version",
|
|
2828
|
+
dry_run=dry_run,
|
|
2829
|
+
batch=True,
|
|
2830
|
+
check=False,
|
|
2831
|
+
)
|
|
2832
|
+
if not dry_run and version.returncode == 0:
|
|
2833
|
+
# Printed rather than enforced. Peers running different versions is
|
|
2834
|
+
# a real hazard, but it is also a legitimate mid-migration state,
|
|
2835
|
+
# and a check that refuses it would be the wrong place to find out.
|
|
2836
|
+
print(f"+ {peer.name}: rosotacom {version.stdout.strip() or 'unknown'}")
|
|
2837
|
+
|
|
2838
|
+
|
|
2646
2839
|
def _ota_prepare_hosts(args: argparse.Namespace, runtime: RuntimeConfig, plan: OtaSmokePlan) -> None:
|
|
2647
2840
|
if not runtime.rosotacom_config:
|
|
2648
2841
|
raise RuntimeError("ota-smoke requires an active rosotacom.yaml project.")
|
|
2649
2842
|
dry_run = bool(getattr(args, "dry_run", False))
|
|
2843
|
+
if plan.install_mode == "checkout":
|
|
2844
|
+
_ota_verify_checkouts(plan, dry_run=dry_run)
|
|
2845
|
+
return
|
|
2650
2846
|
from_pin = plan.install_mode == "pin"
|
|
2651
2847
|
source_checkout: Path | None = None
|
|
2652
2848
|
temporary_bundle: Path | None = None
|
|
@@ -2924,6 +3120,7 @@ def _ota_start_peers(
|
|
|
2924
3120
|
command = _ota_rosotacom_command(
|
|
2925
3121
|
plan,
|
|
2926
3122
|
_ota_start_parts(target, peer_name, instance_id, peer_args, mode=mode, link_trace_parts=link_trace_parts),
|
|
3123
|
+
peer,
|
|
2927
3124
|
)
|
|
2928
3125
|
_ota_run(peer, command, label=f"{peer_name}: start {target.name}", dry_run=dry_run)
|
|
2929
3126
|
|
|
@@ -2940,7 +3137,7 @@ def _ota_start_session_publishers(
|
|
|
2940
3137
|
peer_args = _ota_peer_address_args(plan)
|
|
2941
3138
|
for peer_name in sorted(plan.peers):
|
|
2942
3139
|
peer = plan.peers[peer_name]
|
|
2943
|
-
command = _ota_rosotacom_command(plan, _ota_publish_parts(target, peer_name, peer_args))
|
|
3140
|
+
command = _ota_rosotacom_command(plan, _ota_publish_parts(target, peer_name, peer_args), peer)
|
|
2944
3141
|
result = _ota_run(peer, command, label=f"{peer_name}: start synthetic publishers", dry_run=dry_run, check=False)
|
|
2945
3142
|
_print_completed_output(result)
|
|
2946
3143
|
if result.returncode != 0:
|
|
@@ -2958,7 +3155,7 @@ def _ota_stop_session_publishers(
|
|
|
2958
3155
|
peer_args = _ota_peer_address_args(plan)
|
|
2959
3156
|
for peer_name in sorted(plan.peers):
|
|
2960
3157
|
peer = plan.peers[peer_name]
|
|
2961
|
-
command = _ota_rosotacom_command(plan, _ota_publish_parts(target, peer_name, peer_args, stop=True))
|
|
3158
|
+
command = _ota_rosotacom_command(plan, _ota_publish_parts(target, peer_name, peer_args, stop=True), peer)
|
|
2962
3159
|
_ota_run(peer, command, label=f"{peer_name}: stop synthetic publishers", dry_run=dry_run, check=False)
|
|
2963
3160
|
|
|
2964
3161
|
|
|
@@ -2974,7 +3171,7 @@ def _ota_verify_delivery(
|
|
|
2974
3171
|
print("OTA smoke: running status/expectation checks on every peer.")
|
|
2975
3172
|
for peer_name in sorted(plan.peers):
|
|
2976
3173
|
peer = plan.peers[peer_name]
|
|
2977
|
-
command = _ota_rosotacom_command(plan, _ota_test_parts(target, instance_id, profile=profile))
|
|
3174
|
+
command = _ota_rosotacom_command(plan, _ota_test_parts(target, instance_id, profile=profile), peer)
|
|
2978
3175
|
result = _ota_run(peer, command, label=f"{peer_name}: rosotacom test", dry_run=dry_run, check=False)
|
|
2979
3176
|
if result.returncode != 0:
|
|
2980
3177
|
_ota_print_failure_output(f"{peer_name}: rosotacom test", result)
|
|
@@ -2997,14 +3194,14 @@ def _ota_verify_isolation(
|
|
|
2997
3194
|
peer_args = _ota_peer_address_args(plan)
|
|
2998
3195
|
errors: list[str] = []
|
|
2999
3196
|
print(f"OTA smoke: checking isolation from {source_name} to {receiver_name}.")
|
|
3000
|
-
publish = _ota_rosotacom_command(plan, _ota_probe_publish_parts(target, source_name, peer_args, stop=False))
|
|
3197
|
+
publish = _ota_rosotacom_command(plan, _ota_probe_publish_parts(target, source_name, peer_args, stop=False), source)
|
|
3001
3198
|
published = _ota_run(source, publish, label=f"{source_name}: publish isolation probe", dry_run=dry_run, check=False)
|
|
3002
3199
|
if published.returncode != 0:
|
|
3003
3200
|
_ota_print_failure_output(f"{source_name}: publish isolation probe", published)
|
|
3004
3201
|
errors.append(f"{source_name}: isolation probe publisher failed")
|
|
3005
3202
|
return errors
|
|
3006
3203
|
_print_completed_output(published)
|
|
3007
|
-
check = _ota_rosotacom_command(plan, _ota_probe_check_parts(target, receiver_name, peer_args))
|
|
3204
|
+
check = _ota_rosotacom_command(plan, _ota_probe_check_parts(target, receiver_name, peer_args), receiver)
|
|
3008
3205
|
checked = _ota_run(
|
|
3009
3206
|
receiver,
|
|
3010
3207
|
check,
|
|
@@ -3017,7 +3214,7 @@ def _ota_verify_isolation(
|
|
|
3017
3214
|
errors.append(f"{receiver_name}: isolation probe crossed OTA boundary")
|
|
3018
3215
|
else:
|
|
3019
3216
|
_print_completed_output(checked)
|
|
3020
|
-
stop = _ota_rosotacom_command(plan, _ota_probe_publish_parts(target, source_name, peer_args, stop=True))
|
|
3217
|
+
stop = _ota_rosotacom_command(plan, _ota_probe_publish_parts(target, source_name, peer_args, stop=True), source)
|
|
3021
3218
|
stopped = _ota_run(source, stop, label=f"{source_name}: stop isolation probe", dry_run=dry_run, check=False)
|
|
3022
3219
|
_print_completed_output(stopped)
|
|
3023
3220
|
return errors
|
|
@@ -3046,7 +3243,7 @@ def _ota_verify_content_integrity(
|
|
|
3046
3243
|
for receiver_name, receiver in plan.peers.items():
|
|
3047
3244
|
for topic, msg_type, field, expected in _content_integrity_specs(cfg, receiver_name):
|
|
3048
3245
|
parts = _ota_content_check_parts(target, receiver_name, peer_args, topic, msg_type, field, expected)
|
|
3049
|
-
cmd = _ota_rosotacom_command(plan, parts)
|
|
3246
|
+
cmd = _ota_rosotacom_command(plan, parts, receiver)
|
|
3050
3247
|
print(f"OTA smoke: checking content integrity for {receiver_name} {topic}.")
|
|
3051
3248
|
result = _ota_run(
|
|
3052
3249
|
receiver, cmd, label=f"{receiver_name}: content integrity {topic}", dry_run=dry_run, check=False
|
|
@@ -3067,16 +3264,16 @@ def _ota_collect_logs(
|
|
|
3067
3264
|
) -> None:
|
|
3068
3265
|
project = shlex.quote(plan.project)
|
|
3069
3266
|
instance_suffix = shlex.quote(f"*_{instance.instance_id}")
|
|
3070
|
-
script = (
|
|
3071
|
-
f"cd {shlex.quote(plan.workdir)} && "
|
|
3072
|
-
f"project_dir=$(dirname {project}) && "
|
|
3073
|
-
f'instance_dir=$(find "$project_dir/session-instances" -mindepth 2 -maxdepth 2 '
|
|
3074
|
-
f"-type d -name {instance_suffix} -print -quit 2>/dev/null) && "
|
|
3075
|
-
'if [ -n "$instance_dir" ]; then '
|
|
3076
|
-
'relative=${instance_dir#"$project_dir"/}; '
|
|
3077
|
-
'tar cz -C "$project_dir" "$relative" 2>/dev/null | base64; fi'
|
|
3078
|
-
)
|
|
3079
3267
|
for peer in plan.peers.values():
|
|
3268
|
+
script = (
|
|
3269
|
+
f"cd {shlex.quote(_ota_peer_workdir(plan, peer))} && "
|
|
3270
|
+
f"project_dir=$(dirname {project}) && "
|
|
3271
|
+
f'instance_dir=$(find "$project_dir/session-instances" -mindepth 2 -maxdepth 2 '
|
|
3272
|
+
f"-type d -name {instance_suffix} -print -quit 2>/dev/null) && "
|
|
3273
|
+
'if [ -n "$instance_dir" ]; then '
|
|
3274
|
+
'relative=${instance_dir#"$project_dir"/}; '
|
|
3275
|
+
'tar cz -C "$project_dir" "$relative" 2>/dev/null | base64; fi'
|
|
3276
|
+
)
|
|
3080
3277
|
result = _ota_run(peer, script, label=f"{peer.name}: collect session-instances", dry_run=dry_run, check=False)
|
|
3081
3278
|
if dry_run or not result.stdout.strip():
|
|
3082
3279
|
continue
|
|
@@ -3139,7 +3336,7 @@ def _ota_stop_peers(
|
|
|
3139
3336
|
peer_args = _ota_peer_address_args(plan)
|
|
3140
3337
|
for peer_name in sorted(plan.peers):
|
|
3141
3338
|
peer = plan.peers[peer_name]
|
|
3142
|
-
command = _ota_rosotacom_command(plan, _ota_stop_parts(target, peer_name, instance_id, peer_args))
|
|
3339
|
+
command = _ota_rosotacom_command(plan, _ota_stop_parts(target, peer_name, instance_id, peer_args), peer)
|
|
3143
3340
|
_ota_run(peer, command, label=f"{peer_name}: stop {target.name}", dry_run=dry_run, check=False)
|
|
3144
3341
|
|
|
3145
3342
|
|
|
@@ -3186,7 +3383,9 @@ def _ota_application_run_script(
|
|
|
3186
3383
|
) -> str:
|
|
3187
3384
|
communication_suffix = _sanitize_docker_name(f"_com_to_{_remote_peer_name(target.cfg, peer_name)}")
|
|
3188
3385
|
label = f"{peer_name}:{application.name}"
|
|
3189
|
-
command = _ota_rosotacom_command(
|
|
3386
|
+
command = _ota_rosotacom_command(
|
|
3387
|
+
plan, _ota_application_parts(target, peer_name, application, instance_id), plan.peers[peer_name]
|
|
3388
|
+
)
|
|
3190
3389
|
return (
|
|
3191
3390
|
f"{_ota_wait_for_running_container_suffix_script(communication_suffix, f'{peer_name}:communication')}; "
|
|
3192
3391
|
f"echo '[INFO] starting native application container:' {shlex.quote(label)}; "
|
|
@@ -3219,6 +3418,7 @@ def _ota_create_tmux(
|
|
|
3219
3418
|
mode="attach",
|
|
3220
3419
|
link_trace_parts=link_trace_parts,
|
|
3221
3420
|
),
|
|
3421
|
+
first_peer,
|
|
3222
3422
|
)
|
|
3223
3423
|
first_script = (
|
|
3224
3424
|
"set -e; "
|
|
@@ -3298,6 +3498,7 @@ def _ota_create_tmux(
|
|
|
3298
3498
|
mode="attach",
|
|
3299
3499
|
link_trace_parts=link_trace_parts,
|
|
3300
3500
|
),
|
|
3501
|
+
peer,
|
|
3301
3502
|
)
|
|
3302
3503
|
script = (
|
|
3303
3504
|
"set -e; "
|
|
@@ -3432,6 +3633,24 @@ def _list_ota_smoke(args: argparse.Namespace) -> int:
|
|
|
3432
3633
|
|
|
3433
3634
|
|
|
3434
3635
|
def _ota_cleanup_hosts(plan: OtaSmokePlan, *, dry_run: bool) -> None:
|
|
3636
|
+
if plan.state_path is None:
|
|
3637
|
+
# No recorded state means this plan came from the command line, so its
|
|
3638
|
+
# install mode is a default rather than a fact about the run. Removing a
|
|
3639
|
+
# workdir on that basis is a destructive act taken on a guess: it is how
|
|
3640
|
+
# a stop that reached no peer still reported doing something. Say what
|
|
3641
|
+
# is missing instead.
|
|
3642
|
+
print(
|
|
3643
|
+
"OTA smoke: skipping cleanup — no deployment state for this run, so its install mode is unknown. "
|
|
3644
|
+
"Pass --state-file if a workdir really needs removing."
|
|
3645
|
+
)
|
|
3646
|
+
return
|
|
3647
|
+
if plan.install_mode == "checkout":
|
|
3648
|
+
# The workdir is the user's repository here. `rm -rf` on it would delete
|
|
3649
|
+
# a checkout with its untracked work — bags, instance artefacts, local
|
|
3650
|
+
# edits — to clean up files this mode never created. There is nothing to
|
|
3651
|
+
# remove: staging is what cleanup undoes, and staging did not happen.
|
|
3652
|
+
print("OTA smoke: nothing to clean up — checkout mode staged nothing.")
|
|
3653
|
+
return
|
|
3435
3654
|
_ota_validate_prepare_workdir(plan.workdir)
|
|
3436
3655
|
for peer in plan.peers.values():
|
|
3437
3656
|
_ota_run(
|
|
@@ -3497,7 +3716,7 @@ def _start_interactive_ota_smoke(args: argparse.Namespace) -> int:
|
|
|
3497
3716
|
print("Local control tmux prefix: Ctrl-b. Send the peer tmux/catmux prefix with Ctrl-b Ctrl-b.")
|
|
3498
3717
|
if target.target_type == "scenario":
|
|
3499
3718
|
for peer_name, peer in plan.peers.items():
|
|
3500
|
-
attach = _ota_rosotacom_command(plan, ["scenario", "attach", target.name, "--identity", peer_name])
|
|
3719
|
+
attach = _ota_rosotacom_command(plan, ["scenario", "attach", target.name, "--identity", peer_name], peer)
|
|
3501
3720
|
attach_cmd = _ota_quote_cmd(_ota_remote_argv(peer, attach, tty=bool(peer.ssh)))
|
|
3502
3721
|
print(f"Manual remote scenario reattach for {peer_name}: {attach_cmd}")
|
|
3503
3722
|
if mode == "attach":
|
|
@@ -8266,6 +8485,16 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
8266
8485
|
_add_peer_arg(ota_smoke_parser)
|
|
8267
8486
|
_add_peer_address_arg(ota_smoke_parser)
|
|
8268
8487
|
_add_peer_ssh_arg(ota_smoke_parser)
|
|
8488
|
+
ota_smoke_parser.add_argument(
|
|
8489
|
+
"--peer-checkout",
|
|
8490
|
+
action="append",
|
|
8491
|
+
default=[],
|
|
8492
|
+
metavar="PEER=PATH",
|
|
8493
|
+
help=(
|
|
8494
|
+
"Absolute path of a peer's project checkout, for --install-mode checkout. "
|
|
8495
|
+
"Required for every peer in that mode; the same repository is at a different path on each machine."
|
|
8496
|
+
),
|
|
8497
|
+
)
|
|
8269
8498
|
ota_smoke_parser.add_argument("--target-type", choices=["auto", "session", "scenario"], default="auto")
|
|
8270
8499
|
ota_smoke_parser.add_argument("--interactive", action="store_true", help="Open a local control tmux UI.")
|
|
8271
8500
|
ota_smoke_parser.add_argument("--stop", action="store_true", help="Stop an OTA smoke run.")
|
|
@@ -8289,7 +8518,9 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
8289
8518
|
help=(
|
|
8290
8519
|
"How the peers get rosotacom. 'source' (default) stages and installs what you are running — "
|
|
8291
8520
|
"right while iterating on rosotacom. 'pin' installs a published release from the index, so the "
|
|
8292
|
-
"peers run the artefact that ships — right when rehearsing a deployment."
|
|
8521
|
+
"peers run the artefact that ships — right when rehearsing a deployment. 'checkout' stages and "
|
|
8522
|
+
"installs nothing: each peer uses its own installed rosotacom and its own project checkout "
|
|
8523
|
+
"(see --peer-checkout), so the run tests the machines as git left them."
|
|
8293
8524
|
),
|
|
8294
8525
|
)
|
|
8295
8526
|
ota_smoke_parser.add_argument(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rosotacom-dev
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.dev8
|
|
4
4
|
Summary: Host CLI for ROS OTA communication sessions.
|
|
5
5
|
Author: develNor
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -460,6 +460,11 @@ rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
|
460
460
|
--install-mode pin # defaults to your own version
|
|
461
461
|
rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
462
462
|
--install-mode pin --install-pin 2.4
|
|
463
|
+
|
|
464
|
+
# test the machines as they are: no staging, no install, their own checkouts
|
|
465
|
+
rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
466
|
+
--peer-ssh b=robot-b --install-mode checkout \
|
|
467
|
+
--peer-checkout a=/home/me/fleet_mgmt --peer-checkout b=/home/robot/fleet_mgmt
|
|
463
468
|
```
|
|
464
469
|
|
|
465
470
|
`source` is right while iterating on rosotacom itself — the peers run the code
|
|
@@ -469,6 +474,23 @@ missing from the wheel, an undeclared dependency) fails in the rehearsal instead
|
|
|
469
474
|
of on the target machine. `source` cannot catch that class of defect by
|
|
470
475
|
construction, because it never builds the artefact that ships.
|
|
471
476
|
|
|
477
|
+
`checkout` answers a different question again: not "does this artefact work" but
|
|
478
|
+
"is *this machine* ready". Nothing is staged and nothing is installed — each
|
|
479
|
+
peer runs the rosotacom it already has, from the project checkout it already
|
|
480
|
+
has, so what is under test is the state git and the machine's own install left
|
|
481
|
+
behind, dependency pins included. Ground truth moves into the repository: push,
|
|
482
|
+
pull, run. It is also the only mode in which a project may reference anything
|
|
483
|
+
outside its own directory — staging copies the project directory, so a mount or
|
|
484
|
+
config path leading above it cannot survive the copy and fails on the peer as a
|
|
485
|
+
missing path.
|
|
486
|
+
|
|
487
|
+
Because the same repository sits at a different absolute path on every machine,
|
|
488
|
+
`--peer-checkout` is required for every peer; the path *inside* the repository
|
|
489
|
+
is taken from your own checkout, so the project has to live in one. Preparation
|
|
490
|
+
becomes verification: each peer is asked whether the checkout, the project file
|
|
491
|
+
and `rosotacom` are there, and each version is printed. `--cleanup` does nothing
|
|
492
|
+
in this mode — there is no staging to undo, and the workdir is your repository.
|
|
493
|
+
|
|
472
494
|
The run manifest records which mode and which version the peers ran, so a result
|
|
473
495
|
can be attributed to an artefact rather than to a working copy.
|
|
474
496
|
|