mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-25 21:19:35 +01:00
Merge #736
736: More `xtasks` and add examples to `rtic` repo r=korken89 a=datdenkikniet This was in #732 before, but decluttering that PR seemed sensible Co-authored-by: datdenkikniet <jcdra1@gmail.com>
This commit is contained in:
commit
55083fb3cc
37 changed files with 3319 additions and 1318 deletions
|
@ -2,13 +2,5 @@
|
||||||
xtask = "run --package xtask --"
|
xtask = "run --package xtask --"
|
||||||
pxtask = "run --package xtask --features rayon --"
|
pxtask = "run --package xtask --features rayon --"
|
||||||
|
|
||||||
[target.thumbv6m-none-eabi]
|
# Don't define the RUSTFLAGS link.x thing here: it messes
|
||||||
runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
|
# up compilation of the usage examples.
|
||||||
|
|
||||||
[target.thumbv7m-none-eabi]
|
|
||||||
runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
|
|
||||||
|
|
||||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
|
||||||
rustflags = [
|
|
||||||
"-C", "link-arg=-Tlink.x",
|
|
||||||
]
|
|
||||||
|
|
53
.github/workflows/build.yml
vendored
53
.github/workflows/build.yml
vendored
|
@ -25,9 +25,6 @@ jobs:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Fail on warnings
|
|
||||||
run: find . -type f -name lib.rs -execdir sed -i 's,//deny_warnings_placeholder_for_ci,#![deny(warnings)],' {} +
|
|
||||||
|
|
||||||
- name: Cache Dependencies
|
- name: Cache Dependencies
|
||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
|
@ -62,13 +59,10 @@ jobs:
|
||||||
rustup target add thumbv8m.base-none-eabi
|
rustup target add thumbv8m.base-none-eabi
|
||||||
rustup target add thumbv8m.main-none-eabi
|
rustup target add thumbv8m.main-none-eabi
|
||||||
|
|
||||||
- name: Fail on warnings
|
|
||||||
run: find . -type f -name lib.rs -execdir sed -i 's,//deny_warnings_placeholder_for_ci,#![deny(warnings)],' {} +
|
|
||||||
|
|
||||||
- name: Cache Dependencies
|
- name: Cache Dependencies
|
||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
- run: cargo xtask --backend ${{ matrix.backend }} check
|
- run: cargo xtask --deny-warnings --backend ${{ matrix.backend }} check
|
||||||
|
|
||||||
# Clippy
|
# Clippy
|
||||||
clippy:
|
clippy:
|
||||||
|
@ -101,13 +95,10 @@ jobs:
|
||||||
- name: Add Rust component clippy
|
- name: Add Rust component clippy
|
||||||
run: rustup component add clippy
|
run: rustup component add clippy
|
||||||
|
|
||||||
- name: Fail on warnings
|
|
||||||
run: find . -type f -name lib.rs -execdir sed -i 's,//deny_warnings_placeholder_for_ci,#![deny(warnings)],' {} +
|
|
||||||
|
|
||||||
- name: Cache Dependencies
|
- name: Cache Dependencies
|
||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
- run: cargo xtask --backend ${{ matrix.backend }} clippy
|
- run: cargo xtask --deny-warnings --backend ${{ matrix.backend }} clippy
|
||||||
|
|
||||||
# Verify all examples, checks
|
# Verify all examples, checks
|
||||||
checkexamples:
|
checkexamples:
|
||||||
|
@ -148,6 +139,35 @@ jobs:
|
||||||
if: ${{ matrix.backend != 'thumbv8-base' }}
|
if: ${{ matrix.backend != 'thumbv8-base' }}
|
||||||
run: cargo xtask --backend ${{ matrix.backend }} example-check
|
run: cargo xtask --backend ${{ matrix.backend }} example-check
|
||||||
|
|
||||||
|
# Check that the usage examples build
|
||||||
|
usageexamples:
|
||||||
|
name: Build usage examples
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
toolchain:
|
||||||
|
- nightly
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install rust ${{ matrix.toolchain }}
|
||||||
|
run: |
|
||||||
|
rustup set profile minimal
|
||||||
|
rustup override set ${{ matrix.toolchain }}
|
||||||
|
|
||||||
|
- name: Configure rust target (v6, v7)
|
||||||
|
run: |
|
||||||
|
rustup target add thumbv7m-none-eabi
|
||||||
|
rustup target add thumbv6m-none-eabi
|
||||||
|
rustup component add rust-src
|
||||||
|
|
||||||
|
- name: Cache Dependencies
|
||||||
|
uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
|
- name: Check the examples
|
||||||
|
run: cargo xtask usage-example-build
|
||||||
|
|
||||||
# Verify the example output with run-pass tests
|
# Verify the example output with run-pass tests
|
||||||
testexamples:
|
testexamples:
|
||||||
name: QEMU run
|
name: QEMU run
|
||||||
|
@ -190,12 +210,8 @@ jobs:
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install -y qemu-system-arm
|
sudo apt install -y qemu-system-arm
|
||||||
|
|
||||||
- name: Fail on warnings
|
|
||||||
working-directory: ./rtic
|
|
||||||
run: sed -i 's,//deny_warnings_placeholder_for_ci,#![deny(warnings)],' src/lib.rs
|
|
||||||
|
|
||||||
- name: Run-pass tests
|
- name: Run-pass tests
|
||||||
run: cargo xtask --backend ${{ matrix.backend }} qemu
|
run: cargo xtask --deny-warnings --backend ${{ matrix.backend }} qemu
|
||||||
|
|
||||||
# Run test suite
|
# Run test suite
|
||||||
tests:
|
tests:
|
||||||
|
@ -231,11 +247,8 @@ jobs:
|
||||||
rustup target add thumbv8m.base-none-eabi
|
rustup target add thumbv8m.base-none-eabi
|
||||||
rustup target add thumbv8m.main-none-eabi
|
rustup target add thumbv8m.main-none-eabi
|
||||||
|
|
||||||
- name: Fail on warnings
|
|
||||||
run: find . -type f -name lib.rs -execdir sed -i 's,//deny_warnings_placeholder_for_ci,#![deny(warnings)],' {} +
|
|
||||||
|
|
||||||
- name: Run cargo test
|
- name: Run cargo test
|
||||||
run: cargo xtask --backend ${{ matrix.backend }} test ${{ matrix.package }}
|
run: cargo xtask --deny-warnings --backend ${{ matrix.backend }} test ${{ matrix.package }}
|
||||||
|
|
||||||
# Build documentation, check links
|
# Build documentation, check links
|
||||||
docs:
|
docs:
|
||||||
|
|
2
examples/.gitignore
vendored
Normal file
2
examples/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/**/*/target
|
||||||
|
!Cargo.lock
|
42
examples/README.md
Normal file
42
examples/README.md
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
# `RTIC examples`
|
||||||
|
|
||||||
|
> Here you can find examples on different aspects of the RTIC scheduler.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
This repo does have example applications based on RTIC framework for popular hardware platforms (for example nRF series and Bluepill).
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
To run these examples, you need to have working environment as described in [Installing the tools](https://rust-embedded.github.io/book/intro/install.html) chapter of **The Embedded Rust Book**.
|
||||||
|
|
||||||
|
Short list:
|
||||||
|
|
||||||
|
* Rust and cargo
|
||||||
|
* Toolchain for your microcontroller
|
||||||
|
* OpenOCD
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
New examples are always welcome!
|
||||||
|
|
||||||
|
## External examples
|
||||||
|
|
||||||
|
Some projects maintain RTIC examples in their own repository. Follow these links to find more RTIC examples.
|
||||||
|
|
||||||
|
- The [`teensy4-rs` project](https://github.com/mciantyre/teensy4-rs) maintains `RTIC v1.0` examples that run on the Teensy 4.0 and 4.1.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Licensed under either of
|
||||||
|
|
||||||
|
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||||
|
[http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0))
|
||||||
|
* MIT license ([LICENSE-MIT](LICENSE-MIT) or [http://opensource.org/licenses/MIT](http://opensource.org/licenses/MIT))
|
||||||
|
|
||||||
|
at your option.
|
||||||
|
|
||||||
|
### Contribution
|
||||||
|
|
||||||
|
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the
|
||||||
|
work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
|
||||||
|
additional terms or conditions.
|
45
examples/rp2040_local_i2c_init/.cargo/config.toml
Normal file
45
examples/rp2040_local_i2c_init/.cargo/config.toml
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
[target.thumbv6m-none-eabi]
|
||||||
|
# uncomment this to make `cargo run` execute programs on QEMU
|
||||||
|
# runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
|
||||||
|
|
||||||
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
|
# uncomment ONE of these three option to make `cargo run` start a GDB session
|
||||||
|
# which option to pick depends on your system
|
||||||
|
# runner = "arm-none-eabi-gdb -q -x openocd.gdb"
|
||||||
|
# runner = "gdb-multiarch -q -x openocd.gdb"
|
||||||
|
# runner = "gdb -q -x openocd.gdb"
|
||||||
|
|
||||||
|
rustflags = [
|
||||||
|
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
|
||||||
|
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
|
||||||
|
"-C", "link-arg=--nmagic",
|
||||||
|
|
||||||
|
# LLD (shipped with the Rust toolchain) is used as the default linker
|
||||||
|
"-C", "link-arg=-Tlink.x",
|
||||||
|
|
||||||
|
# if you run into problems with LLD switch to the GNU linker by commenting out
|
||||||
|
# this line
|
||||||
|
# "-C", "linker=arm-none-eabi-ld",
|
||||||
|
|
||||||
|
# if you need to link to pre-compiled C libraries provided by a C toolchain
|
||||||
|
# use GCC as the linker by commenting out both lines above and then
|
||||||
|
# uncommenting the three lines below
|
||||||
|
# "-C", "linker=arm-none-eabi-gcc",
|
||||||
|
# "-C", "link-arg=-Wl,-Tlink.x",
|
||||||
|
# "-C", "link-arg=-nostartfiles",
|
||||||
|
]
|
||||||
|
|
||||||
|
[build]
|
||||||
|
# Pick ONE of these compilation targets
|
||||||
|
target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
|
||||||
|
# target = "thumbv7m-none-eabi" # Cortex-M3
|
||||||
|
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
|
||||||
|
# target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
||||||
|
# target = "thumbv8m.base-none-eabi" # Cortex-M23
|
||||||
|
# target = "thumbv8m.main-none-eabi" # Cortex-M33 (no FPU)
|
||||||
|
# target = "thumbv8m.main-none-eabihf" # Cortex-M33 (with FPU)
|
||||||
|
|
||||||
|
# thumbv7m-none-eabi is not coming with core and alloc, compile myself
|
||||||
|
[unstable]
|
||||||
|
mtime-on-use = true
|
||||||
|
build-std = ["core", "alloc"]
|
533
examples/rp2040_local_i2c_init/Cargo.lock
generated
Normal file
533
examples/rp2040_local_i2c_init/Cargo.lock
generated
Normal file
|
@ -0,0 +1,533 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayvec"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atomic-polyfill"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c314e70d181aa6053b26e3f7fbf86d1dfff84f816a6175b967666b3506ef7289"
|
||||||
|
dependencies = [
|
||||||
|
"critical-section",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bare-metal"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
|
||||||
|
dependencies = [
|
||||||
|
"rustc_version",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bare-metal"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitfield"
|
||||||
|
version = "0.13.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cortex-m"
|
||||||
|
version = "0.7.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
|
||||||
|
dependencies = [
|
||||||
|
"bare-metal 0.2.5",
|
||||||
|
"bitfield",
|
||||||
|
"embedded-hal",
|
||||||
|
"volatile-register",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cortex-m-rt"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1"
|
||||||
|
dependencies = [
|
||||||
|
"cortex-m-rt-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cortex-m-rt-macros"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc-any"
|
||||||
|
version = "2.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "774646b687f63643eb0f4bf13dc263cb581c8c9e57973b6ddf78bda3994d88df"
|
||||||
|
dependencies = [
|
||||||
|
"debug-helper",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "critical-section"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "debug-helper"
|
||||||
|
version = "0.3.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-dma"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446"
|
||||||
|
dependencies = [
|
||||||
|
"stable_deref_trait",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-hal"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
|
||||||
|
dependencies = [
|
||||||
|
"nb 0.1.3",
|
||||||
|
"void",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fugit"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ab17bb279def6720d058cb6c052249938e7f99260ab534879281a95367a87e5"
|
||||||
|
dependencies = [
|
||||||
|
"gcd",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-core"
|
||||||
|
version = "0.3.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-task"
|
||||||
|
version = "0.3.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-util"
|
||||||
|
version = "0.3.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"pin-project-lite",
|
||||||
|
"pin-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gcd"
|
||||||
|
version = "2.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nb"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
|
||||||
|
dependencies = [
|
||||||
|
"nb 1.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nb"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_enum"
|
||||||
|
version = "0.5.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
|
||||||
|
dependencies = [
|
||||||
|
"num_enum_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_enum_derive"
|
||||||
|
version = "0.5.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "panic-probe"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa6fa5645ef5a760cd340eaa92af9c1ce131c8c09e7f8926d8a24b59d26652b9"
|
||||||
|
dependencies = [
|
||||||
|
"cortex-m",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pio"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "76e09694b50f89f302ed531c1f2a7569f0be5867aee4ab4f8f729bbeec0078e3"
|
||||||
|
dependencies = [
|
||||||
|
"arrayvec",
|
||||||
|
"num_enum",
|
||||||
|
"paste",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.56"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rp-pico"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aab28f6f4e19cec2d61b64cdd685e69794b81c579fd3b765579c46018fe616d0"
|
||||||
|
dependencies = [
|
||||||
|
"cortex-m",
|
||||||
|
"cortex-m-rt",
|
||||||
|
"fugit",
|
||||||
|
"rp2040-boot2",
|
||||||
|
"rp2040-hal",
|
||||||
|
"usb-device",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rp2040-boot2"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c773ec49b836077aa144b58dc7654a243e1eecdb6cf0d25361ae7c7600fabd8"
|
||||||
|
dependencies = [
|
||||||
|
"crc-any",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rp2040-hal"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd64ea14218eaa350e5cf1023b7a84c267f092e4a64b69129dc460e53412bed8"
|
||||||
|
dependencies = [
|
||||||
|
"cortex-m",
|
||||||
|
"critical-section",
|
||||||
|
"embedded-dma",
|
||||||
|
"embedded-hal",
|
||||||
|
"fugit",
|
||||||
|
"itertools",
|
||||||
|
"nb 1.1.0",
|
||||||
|
"paste",
|
||||||
|
"pio",
|
||||||
|
"rand_core",
|
||||||
|
"rp2040-hal-macros",
|
||||||
|
"rp2040-pac",
|
||||||
|
"usb-device",
|
||||||
|
"vcell",
|
||||||
|
"void",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rp2040-hal-macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "86479063e497efe1ae81995ef9071f54fd1c7427e04d6c5b84cde545ff672a5e"
|
||||||
|
dependencies = [
|
||||||
|
"cortex-m-rt",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rp2040-pac"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9192cafbb40d717c9e0ddf767aaf9c69fee1b4e48d22ed853b57b11f6d9f3d7e"
|
||||||
|
dependencies = [
|
||||||
|
"cortex-m",
|
||||||
|
"cortex-m-rt",
|
||||||
|
"vcell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rp2040_local_i2c_init"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cortex-m",
|
||||||
|
"embedded-hal",
|
||||||
|
"fugit",
|
||||||
|
"panic-probe",
|
||||||
|
"rp-pico",
|
||||||
|
"rtic",
|
||||||
|
"rtic-monotonics",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rtic"
|
||||||
|
version = "2.0.0-alpha.1"
|
||||||
|
dependencies = [
|
||||||
|
"atomic-polyfill",
|
||||||
|
"bare-metal 1.0.0",
|
||||||
|
"cortex-m",
|
||||||
|
"critical-section",
|
||||||
|
"rtic-core",
|
||||||
|
"rtic-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rtic-common"
|
||||||
|
version = "1.0.0-alpha.0"
|
||||||
|
dependencies = [
|
||||||
|
"critical-section",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rtic-core"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rtic-macros"
|
||||||
|
version = "2.0.0-alpha.0"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rtic-monotonics"
|
||||||
|
version = "1.0.0-alpha.1"
|
||||||
|
dependencies = [
|
||||||
|
"atomic-polyfill",
|
||||||
|
"cfg-if",
|
||||||
|
"cortex-m",
|
||||||
|
"fugit",
|
||||||
|
"rp2040-pac",
|
||||||
|
"rtic-time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rtic-time"
|
||||||
|
version = "1.0.0-alpha.1"
|
||||||
|
dependencies = [
|
||||||
|
"critical-section",
|
||||||
|
"futures-util",
|
||||||
|
"rtic-common",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_version"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||||
|
dependencies = [
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||||
|
dependencies = [
|
||||||
|
"semver-parser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver-parser"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stable_deref_trait"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.109"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "usb-device"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vcell"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "void"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "volatile-register"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6"
|
||||||
|
dependencies = [
|
||||||
|
"vcell",
|
||||||
|
]
|
38
examples/rp2040_local_i2c_init/Cargo.toml
Normal file
38
examples/rp2040_local_i2c_init/Cargo.toml
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
[package]
|
||||||
|
name = "rp2040_local_i2c_init"
|
||||||
|
categories = ["embedded", "no-std"]
|
||||||
|
description = "Example task local initialized resources for Raspberry Pi Pico"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
|
||||||
|
[dependencies.rtic]
|
||||||
|
path = "../../rtic"
|
||||||
|
version = "=2.0.0-alpha.1"
|
||||||
|
features = ["thumbv6-backend"]
|
||||||
|
|
||||||
|
[dependencies.rtic-monotonics]
|
||||||
|
path = "../../rtic-monotonics"
|
||||||
|
version = "=1.0.0-alpha.1"
|
||||||
|
features = ["rp2040"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
cortex-m = "0.7"
|
||||||
|
embedded-hal = { version = "0.2.7", features = ["unproven"] }
|
||||||
|
fugit = "0.3"
|
||||||
|
rp-pico = "0.7.0"
|
||||||
|
panic-probe = "0.3"
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
opt-level = 1
|
||||||
|
codegen-units = 16
|
||||||
|
debug = true
|
||||||
|
lto = false
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = "s" # optimize for size
|
||||||
|
codegen-units = 1 # better optimizations
|
||||||
|
debug = true # symbols are nice and they don't increase the size on Flash
|
||||||
|
lto = true # better optimzations
|
39
examples/rp2040_local_i2c_init/Embed.toml
Normal file
39
examples/rp2040_local_i2c_init/Embed.toml
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
[default.probe]
|
||||||
|
protocol = "Swd"
|
||||||
|
speed = 20000
|
||||||
|
# If you only have one probe cargo embed will pick automatically
|
||||||
|
# Otherwise: add your probe's VID/PID/serial to filter
|
||||||
|
|
||||||
|
## rust-dap
|
||||||
|
# usb_vid = "6666"
|
||||||
|
# usb_pid = "4444"
|
||||||
|
# serial = "test"
|
||||||
|
|
||||||
|
|
||||||
|
[default.flashing]
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
[default.reset]
|
||||||
|
enabled = true
|
||||||
|
halt_afterwards = false
|
||||||
|
|
||||||
|
[default.general]
|
||||||
|
chip = "RP2040"
|
||||||
|
log_level = "WARN"
|
||||||
|
# RP2040 does not support connect_under_reset
|
||||||
|
connect_under_reset = false
|
||||||
|
|
||||||
|
[default.rtt]
|
||||||
|
enabled = true
|
||||||
|
up_mode = "NoBlockSkip"
|
||||||
|
channels = [
|
||||||
|
{ up = 0, down = 0, name = "name", up_mode = "NoBlockSkip", format = "Defmt" },
|
||||||
|
]
|
||||||
|
timeout = 3000
|
||||||
|
show_timestamps = true
|
||||||
|
log_enabled = false
|
||||||
|
log_path = "./logs"
|
||||||
|
|
||||||
|
[default.gdb]
|
||||||
|
enabled = true
|
||||||
|
gdb_connection_string = "127.0.0.1:2345"
|
31
examples/rp2040_local_i2c_init/build.rs
Normal file
31
examples/rp2040_local_i2c_init/build.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
//! This build script copies the `memory.x` file from the crate root into
|
||||||
|
//! a directory where the linker can always find it at build time.
|
||||||
|
//! For many projects this is optional, as the linker always searches the
|
||||||
|
//! project root directory -- wherever `Cargo.toml` is. However, if you
|
||||||
|
//! are using a workspace or have a more complicated build setup, this
|
||||||
|
//! build script becomes required. Additionally, by requesting that
|
||||||
|
//! Cargo re-run the build script whenever `memory.x` is changed,
|
||||||
|
//! updating `memory.x` ensures a rebuild of the application with the
|
||||||
|
//! new memory settings.
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Put `memory.x` in our output directory and ensure it's
|
||||||
|
// on the linker search path.
|
||||||
|
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||||
|
File::create(out.join("memory.x"))
|
||||||
|
.unwrap()
|
||||||
|
.write_all(include_bytes!("memory.x"))
|
||||||
|
.unwrap();
|
||||||
|
println!("cargo:rustc-link-search={}", out.display());
|
||||||
|
|
||||||
|
// By default, Cargo will re-run a build script whenever
|
||||||
|
// any file in the project changes. By specifying `memory.x`
|
||||||
|
// here, we ensure the build script is only re-run when
|
||||||
|
// `memory.x` is changed.
|
||||||
|
println!("cargo:rerun-if-changed=memory.x");
|
||||||
|
}
|
15
examples/rp2040_local_i2c_init/memory.x
Normal file
15
examples/rp2040_local_i2c_init/memory.x
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
MEMORY {
|
||||||
|
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
|
||||||
|
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
|
||||||
|
RAM : ORIGIN = 0x20000000, LENGTH = 256K
|
||||||
|
}
|
||||||
|
|
||||||
|
EXTERN(BOOT2_FIRMWARE)
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
/* ### Boot loader */
|
||||||
|
.boot2 ORIGIN(BOOT2) :
|
||||||
|
{
|
||||||
|
KEEP(*(.boot2));
|
||||||
|
} > BOOT2
|
||||||
|
} INSERT BEFORE .text;
|
115
examples/rp2040_local_i2c_init/src/main.rs
Normal file
115
examples/rp2040_local_i2c_init/src/main.rs
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
#[rtic::app(
|
||||||
|
device = rp_pico::hal::pac,
|
||||||
|
dispatchers = [TIMER_IRQ_1]
|
||||||
|
)]
|
||||||
|
mod app {
|
||||||
|
use rp_pico::hal::{
|
||||||
|
clocks, gpio,
|
||||||
|
gpio::pin::bank0::{Gpio2, Gpio25, Gpio3},
|
||||||
|
gpio::pin::PushPullOutput,
|
||||||
|
pac,
|
||||||
|
sio::Sio,
|
||||||
|
watchdog::Watchdog,
|
||||||
|
I2C,
|
||||||
|
};
|
||||||
|
use rp_pico::XOSC_CRYSTAL_FREQ;
|
||||||
|
|
||||||
|
use core::mem::MaybeUninit;
|
||||||
|
use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin};
|
||||||
|
use fugit::RateExtU32;
|
||||||
|
use rtic_monotonics::rp2040::*;
|
||||||
|
|
||||||
|
use panic_probe as _;
|
||||||
|
|
||||||
|
type I2CBus = I2C<
|
||||||
|
pac::I2C1,
|
||||||
|
(
|
||||||
|
gpio::Pin<Gpio2, gpio::FunctionI2C>,
|
||||||
|
gpio::Pin<Gpio3, gpio::FunctionI2C>,
|
||||||
|
),
|
||||||
|
>;
|
||||||
|
|
||||||
|
#[shared]
|
||||||
|
struct Shared {}
|
||||||
|
|
||||||
|
#[local]
|
||||||
|
struct Local {
|
||||||
|
led: gpio::Pin<Gpio25, PushPullOutput>,
|
||||||
|
i2c: &'static mut I2CBus,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[init(local=[
|
||||||
|
// Task local initialized resources are static
|
||||||
|
// Here we use MaybeUninit to allow for initialization in init()
|
||||||
|
// This enables its usage in driver initialization
|
||||||
|
i2c_ctx: MaybeUninit<I2CBus> = MaybeUninit::uninit()
|
||||||
|
])]
|
||||||
|
fn init(mut ctx: init::Context) -> (Shared, Local) {
|
||||||
|
// Initialize the interrupt for the RP2040 timer and obtain the token
|
||||||
|
// proving that we have.
|
||||||
|
let rp2040_timer_token = rtic_monotonics::create_rp2040_monotonic_token!();
|
||||||
|
// Configure the clocks, watchdog - The default is to generate a 125 MHz system clock
|
||||||
|
Timer::start(ctx.device.TIMER, &mut ctx.device.RESETS, rp2040_timer_token); // default rp2040 clock-rate is 125MHz
|
||||||
|
let mut watchdog = Watchdog::new(ctx.device.WATCHDOG);
|
||||||
|
let clocks = clocks::init_clocks_and_plls(
|
||||||
|
XOSC_CRYSTAL_FREQ,
|
||||||
|
ctx.device.XOSC,
|
||||||
|
ctx.device.CLOCKS,
|
||||||
|
ctx.device.PLL_SYS,
|
||||||
|
ctx.device.PLL_USB,
|
||||||
|
&mut ctx.device.RESETS,
|
||||||
|
&mut watchdog,
|
||||||
|
)
|
||||||
|
.ok()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Init LED pin
|
||||||
|
let sio = Sio::new(ctx.device.SIO);
|
||||||
|
let gpioa = rp_pico::Pins::new(
|
||||||
|
ctx.device.IO_BANK0,
|
||||||
|
ctx.device.PADS_BANK0,
|
||||||
|
sio.gpio_bank0,
|
||||||
|
&mut ctx.device.RESETS,
|
||||||
|
);
|
||||||
|
let mut led = gpioa.led.into_push_pull_output();
|
||||||
|
led.set_low().unwrap();
|
||||||
|
|
||||||
|
// Init I2C pins
|
||||||
|
let sda_pin = gpioa.gpio2.into_mode::<gpio::FunctionI2C>();
|
||||||
|
let scl_pin = gpioa.gpio3.into_mode::<gpio::FunctionI2C>();
|
||||||
|
|
||||||
|
// Init I2C itself, using MaybeUninit to overwrite the previously
|
||||||
|
// uninitialized i2c_ctx variable without dropping its value
|
||||||
|
// (i2c_ctx definined in init local resources above)
|
||||||
|
let i2c_tmp: &'static mut _ = ctx.local.i2c_ctx.write(I2C::i2c1(
|
||||||
|
ctx.device.I2C1,
|
||||||
|
sda_pin,
|
||||||
|
scl_pin,
|
||||||
|
100.kHz(),
|
||||||
|
&mut ctx.device.RESETS,
|
||||||
|
&clocks.system_clock,
|
||||||
|
));
|
||||||
|
|
||||||
|
// Spawn heartbeat task
|
||||||
|
heartbeat::spawn().ok();
|
||||||
|
|
||||||
|
// Return resources and timer
|
||||||
|
(Shared {}, Local { led, i2c: i2c_tmp })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(local = [i2c, led])]
|
||||||
|
async fn heartbeat(ctx: heartbeat::Context) {
|
||||||
|
// Flicker the built-in LED
|
||||||
|
_ = ctx.local.led.toggle();
|
||||||
|
|
||||||
|
// Congrats, you can use your i2c and have access to it here,
|
||||||
|
// now to do something with it!
|
||||||
|
|
||||||
|
// Re-spawn this task after 1 second
|
||||||
|
Timer::delay(1000.millis()).await;
|
||||||
|
}
|
||||||
|
}
|
45
examples/stm32f3_blinky/.cargo/config.toml
Normal file
45
examples/stm32f3_blinky/.cargo/config.toml
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
[target.thumbv7m-none-eabi]
|
||||||
|
# uncomment this to make `cargo run` execute programs on QEMU
|
||||||
|
# runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
|
||||||
|
|
||||||
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
|
# uncomment ONE of these three option to make `cargo run` start a GDB session
|
||||||
|
# which option to pick depends on your system
|
||||||
|
# runner = "arm-none-eabi-gdb -q -x openocd.gdb"
|
||||||
|
# runner = "gdb-multiarch -q -x openocd.gdb"
|
||||||
|
# runner = "gdb -q -x openocd.gdb"
|
||||||
|
|
||||||
|
rustflags = [
|
||||||
|
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
|
||||||
|
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
|
||||||
|
"-C", "link-arg=--nmagic",
|
||||||
|
|
||||||
|
# LLD (shipped with the Rust toolchain) is used as the default linker
|
||||||
|
"-C", "link-arg=-Tlink.x",
|
||||||
|
|
||||||
|
# if you run into problems with LLD switch to the GNU linker by commenting out
|
||||||
|
# this line
|
||||||
|
# "-C", "linker=arm-none-eabi-ld",
|
||||||
|
|
||||||
|
# if you need to link to pre-compiled C libraries provided by a C toolchain
|
||||||
|
# use GCC as the linker by commenting out both lines above and then
|
||||||
|
# uncommenting the three lines below
|
||||||
|
# "-C", "linker=arm-none-eabi-gcc",
|
||||||
|
# "-C", "link-arg=-Wl,-Tlink.x",
|
||||||
|
# "-C", "link-arg=-nostartfiles",
|
||||||
|
]
|
||||||
|
|
||||||
|
[build]
|
||||||
|
# Pick ONE of these compilation targets
|
||||||
|
# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
|
||||||
|
target = "thumbv7m-none-eabi" # Cortex-M3
|
||||||
|
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
|
||||||
|
# target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
||||||
|
# target = "thumbv8m.base-none-eabi" # Cortex-M23
|
||||||
|
# target = "thumbv8m.main-none-eabi" # Cortex-M33 (no FPU)
|
||||||
|
# target = "thumbv8m.main-none-eabihf" # Cortex-M33 (with FPU)
|
||||||
|
|
||||||
|
# thumbv7m-none-eabi is not coming with core and alloc, compile myself
|
||||||
|
[unstable]
|
||||||
|
mtime-on-use = true
|
||||||
|
build-std = ["core", "alloc"]
|
635
examples/stm32f3_blinky/Cargo.lock
generated
Normal file
635
examples/stm32f3_blinky/Cargo.lock
generated
Normal file
|
@ -0,0 +1,635 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atomic-polyfill"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d299f547288d6db8d5c3a2916f7b2f66134b15b8c1ac1c4357dd3b8752af7bb2"
|
||||||
|
dependencies = [
|
||||||
|
"critical-section",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bare-metal"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
|
||||||
|
dependencies = [
|
||||||
|
"rustc_version",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bare-metal"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitfield"
|
||||||
|
version = "0.13.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bxcan"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4b13b4b2ea9ab2ba924063ebb86ad895cb79f4a79bf90f27949eb20c335b30f9"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"nb 1.0.0",
|
||||||
|
"vcell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
|
||||||
|
dependencies = [
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cortex-m"
|
||||||
|
version = "0.7.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
|
||||||
|
dependencies = [
|
||||||
|
"bare-metal 0.2.5",
|
||||||
|
"bitfield",
|
||||||
|
"critical-section",
|
||||||
|
"embedded-hal",
|
||||||
|
"volatile-register",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cortex-m-rt"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1"
|
||||||
|
dependencies = [
|
||||||
|
"cortex-m-rt-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cortex-m-rt-macros"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "critical-section"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.14.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c0808e1bd8671fb44a113a14e13497557533369847788fa2ae912b6ebfce9fa8"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"darling_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.14.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.14.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-dma"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446"
|
||||||
|
dependencies = [
|
||||||
|
"stable_deref_trait",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-hal"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
|
||||||
|
dependencies = [
|
||||||
|
"nb 0.1.3",
|
||||||
|
"void",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-time"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d7a4b4d10ac48d08bfe3db7688c402baadb244721f30a77ce360bd24c3dffe58"
|
||||||
|
dependencies = [
|
||||||
|
"num",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enumset"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "19be8061a06ab6f3a6cf21106c873578bf01bd42ad15e0311a9c76161cb1c753"
|
||||||
|
dependencies = [
|
||||||
|
"enumset_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enumset_derive"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "03e7b551eba279bf0fa88b83a46330168c1560a52a94f5126f892f0b364ab3e0"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fnv"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fugit"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ab17bb279def6720d058cb6c052249938e7f99260ab534879281a95367a87e5"
|
||||||
|
dependencies = [
|
||||||
|
"gcd",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-core"
|
||||||
|
version = "0.3.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-task"
|
||||||
|
version = "0.3.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-util"
|
||||||
|
version = "0.3.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"pin-project-lite",
|
||||||
|
"pin-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gcd"
|
||||||
|
version = "2.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nb"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
|
||||||
|
dependencies = [
|
||||||
|
"nb 1.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nb"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f"
|
||||||
|
dependencies = [
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.43"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "panic-rtt-target"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d6ab67bc881453e4c90f958c657c1303670ea87bc1a16e87fd71a40f656dce9"
|
||||||
|
dependencies = [
|
||||||
|
"cortex-m",
|
||||||
|
"rtt-target",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.51"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rtcc"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3623619ce77c09a7d87cf7c61c5c887b9c7dee8805f66af6c4aa5824be4d9930"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rtic"
|
||||||
|
version = "2.0.0-alpha.1"
|
||||||
|
dependencies = [
|
||||||
|
"atomic-polyfill",
|
||||||
|
"bare-metal 1.0.0",
|
||||||
|
"cortex-m",
|
||||||
|
"critical-section",
|
||||||
|
"rtic-core",
|
||||||
|
"rtic-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rtic-common"
|
||||||
|
version = "1.0.0-alpha.0"
|
||||||
|
dependencies = [
|
||||||
|
"critical-section",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rtic-core"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rtic-macros"
|
||||||
|
version = "2.0.0-alpha.0"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rtic-monotonics"
|
||||||
|
version = "1.0.0-alpha.1"
|
||||||
|
dependencies = [
|
||||||
|
"atomic-polyfill",
|
||||||
|
"cfg-if",
|
||||||
|
"cortex-m",
|
||||||
|
"fugit",
|
||||||
|
"rtic-time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rtic-time"
|
||||||
|
version = "1.0.0-alpha.1"
|
||||||
|
dependencies = [
|
||||||
|
"critical-section",
|
||||||
|
"futures-util",
|
||||||
|
"rtic-common",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rtt-target"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "065d6058bb1204f51a562a67209e1817cf714759d5cf845aa45c75fa7b0b9d9b"
|
||||||
|
dependencies = [
|
||||||
|
"cortex-m",
|
||||||
|
"ufmt-write",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_version"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||||
|
dependencies = [
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||||
|
dependencies = [
|
||||||
|
"semver-parser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver-parser"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slice-group-by"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stable_deref_trait"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stm32-usbd"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c6c94998f166d66b210a164648a0b7866428d8f1e0740bf8a4c5edd89d4750c1"
|
||||||
|
dependencies = [
|
||||||
|
"cortex-m",
|
||||||
|
"usb-device",
|
||||||
|
"vcell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stm32f3"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "265cda62ac13307414de4aca58dbbbd8038ddba85cffbb335823aa216f2e3200"
|
||||||
|
dependencies = [
|
||||||
|
"bare-metal 1.0.0",
|
||||||
|
"cortex-m",
|
||||||
|
"cortex-m-rt",
|
||||||
|
"vcell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stm32f3-blinky"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"embedded-hal",
|
||||||
|
"panic-rtt-target",
|
||||||
|
"rtic",
|
||||||
|
"rtic-monotonics",
|
||||||
|
"rtt-target",
|
||||||
|
"stm32f3xx-hal",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stm32f3xx-hal"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c9d827f02df3826371c897404dfbea8a1abd544eed9d6cdc3e5f6e9f04b9e06"
|
||||||
|
dependencies = [
|
||||||
|
"bare-metal 1.0.0",
|
||||||
|
"bxcan",
|
||||||
|
"cfg-if",
|
||||||
|
"cortex-m",
|
||||||
|
"cortex-m-rt",
|
||||||
|
"embedded-dma",
|
||||||
|
"embedded-hal",
|
||||||
|
"embedded-time",
|
||||||
|
"enumset",
|
||||||
|
"nb 1.0.0",
|
||||||
|
"paste",
|
||||||
|
"rtcc",
|
||||||
|
"slice-group-by",
|
||||||
|
"stm32-usbd",
|
||||||
|
"stm32f3",
|
||||||
|
"void",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.109"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ufmt-write"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "usb-device"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vcell"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "void"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "volatile-register"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6"
|
||||||
|
dependencies = [
|
||||||
|
"vcell",
|
||||||
|
]
|
45
examples/stm32f3_blinky/Cargo.toml
Normal file
45
examples/stm32f3_blinky/Cargo.toml
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
[package]
|
||||||
|
authors = ["Simsys <winfried.simon@gmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
readme = "README.md"
|
||||||
|
name = "stm32f3-blinky"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
|
||||||
|
[dependencies.rtic]
|
||||||
|
path = "../../rtic"
|
||||||
|
version = "=2.0.0-alpha.1"
|
||||||
|
features = ["thumbv7-backend"]
|
||||||
|
|
||||||
|
[dependencies.rtic-monotonics]
|
||||||
|
path = "../../rtic-monotonics"
|
||||||
|
version = "=1.0.0-alpha.1"
|
||||||
|
features = ["cortex-m-systick"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
embedded-hal = "0.2.7"
|
||||||
|
panic-rtt-target = { version = "0.1.2", features = ["cortex-m"] }
|
||||||
|
rtt-target = { version = "0.3.1", features = ["cortex-m"] }
|
||||||
|
|
||||||
|
[dependencies.stm32f3xx-hal]
|
||||||
|
features = ["stm32f303xc", "rt"]
|
||||||
|
version = "0.9.2"
|
||||||
|
|
||||||
|
# this lets you use `cargo fix`!
|
||||||
|
[[bin]]
|
||||||
|
name = "stm32f3-blinky"
|
||||||
|
test = false
|
||||||
|
bench = false
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
opt-level = 1
|
||||||
|
codegen-units = 16
|
||||||
|
debug = true
|
||||||
|
lto = false
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = "s" # optimize for size
|
||||||
|
codegen-units = 1 # better optimizations
|
||||||
|
debug = true # symbols are nice and they don't increase the size on Flash
|
||||||
|
lto = true # better optimizations
|
9
examples/stm32f3_blinky/Embed.toml
Normal file
9
examples/stm32f3_blinky/Embed.toml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[default.general]
|
||||||
|
chip = "stm32f303re"
|
||||||
|
|
||||||
|
|
||||||
|
[default.rtt]
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
[default.gdb]
|
||||||
|
enabled = false
|
19
examples/stm32f3_blinky/README.md
Normal file
19
examples/stm32f3_blinky/README.md
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# STM32F3 RTIC Blink example
|
||||||
|
|
||||||
|
Working example of simple LED blinking application for STM32 F303 Nucleo-64 board based on the STM32F303RE chip. Example uses schedule API and peripherials access. This example is based on blue-pill blinky example.
|
||||||
|
|
||||||
|
## How-to
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
Run `cargo +nightly build` to compile the code. If you run it for the first time, it will take some time to download and compile dependencies.
|
||||||
|
|
||||||
|
After that, you can use for example the cargo-embed tool to flash and run it
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo +nightly embed
|
||||||
|
```
|
||||||
|
|
||||||
|
### Setup environment, flash and run program
|
||||||
|
|
||||||
|
In the [Discovery Book](https://rust-embedded.github.io/discovery) you find all needed informations to setup the environment, flash the controler and run the program.
|
5
examples/stm32f3_blinky/memory.x
Normal file
5
examples/stm32f3_blinky/memory.x
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
FLASH : ORIGIN = 0x08000000, LENGTH = 256K
|
||||||
|
RAM : ORIGIN = 0x20000000, LENGTH = 40K
|
||||||
|
}
|
74
examples/stm32f3_blinky/src/main.rs
Normal file
74
examples/stm32f3_blinky/src/main.rs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
#![deny(unsafe_code)]
|
||||||
|
#![deny(warnings)]
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use panic_rtt_target as _;
|
||||||
|
use rtic::app;
|
||||||
|
use rtic_monotonics::systick::*;
|
||||||
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
|
use stm32f3xx_hal::gpio::{Output, PushPull, PA5};
|
||||||
|
use stm32f3xx_hal::prelude::*;
|
||||||
|
|
||||||
|
#[app(device = stm32f3xx_hal::pac, peripherals = true, dispatchers = [SPI1])]
|
||||||
|
mod app {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[shared]
|
||||||
|
struct Shared {}
|
||||||
|
|
||||||
|
#[local]
|
||||||
|
struct Local {
|
||||||
|
led: PA5<Output<PushPull>>,
|
||||||
|
state: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[init]
|
||||||
|
fn init(cx: init::Context) -> (Shared, Local) {
|
||||||
|
// Setup clocks
|
||||||
|
let mut flash = cx.device.FLASH.constrain();
|
||||||
|
let mut rcc = cx.device.RCC.constrain();
|
||||||
|
|
||||||
|
// Initialize the systick interrupt & obtain the token to prove that we did
|
||||||
|
let systick_mono_token = rtic_monotonics::create_systick_token!();
|
||||||
|
Systick::start(cx.core.SYST, 36_000_000, systick_mono_token); // default STM32F303 clock-rate is 36MHz
|
||||||
|
|
||||||
|
rtt_init_print!();
|
||||||
|
rprintln!("init");
|
||||||
|
|
||||||
|
let _clocks = rcc
|
||||||
|
.cfgr
|
||||||
|
.use_hse(8.MHz())
|
||||||
|
.sysclk(36.MHz())
|
||||||
|
.pclk1(36.MHz())
|
||||||
|
.freeze(&mut flash.acr);
|
||||||
|
|
||||||
|
// Setup LED
|
||||||
|
let mut gpioa = cx.device.GPIOA.split(&mut rcc.ahb);
|
||||||
|
let mut led = gpioa
|
||||||
|
.pa5
|
||||||
|
.into_push_pull_output(&mut gpioa.moder, &mut gpioa.otyper);
|
||||||
|
led.set_high().unwrap();
|
||||||
|
|
||||||
|
// Schedule the blinking task
|
||||||
|
blink::spawn().ok();
|
||||||
|
|
||||||
|
(Shared {}, Local { led, state: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(local = [led, state])]
|
||||||
|
async fn blink(cx: blink::Context) {
|
||||||
|
loop {
|
||||||
|
rprintln!("blink");
|
||||||
|
if *cx.local.state {
|
||||||
|
cx.local.led.set_high().unwrap();
|
||||||
|
*cx.local.state = false;
|
||||||
|
} else {
|
||||||
|
cx.local.led.set_low().unwrap();
|
||||||
|
*cx.local.state = true;
|
||||||
|
}
|
||||||
|
Systick::delay(1000.millis()).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
//deny_warnings_placeholder_for_ci
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
html_logo_url = "https://raw.githubusercontent.com/rtic-rs/rtic/master/book/en/src/RTIC.svg",
|
html_logo_url = "https://raw.githubusercontent.com/rtic-rs/rtic/master/book/en/src/RTIC.svg",
|
||||||
html_favicon_url = "https://raw.githubusercontent.com/rtic-rs/rtic/master/book/en/src/RTIC.svg"
|
html_favicon_url = "https://raw.githubusercontent.com/rtic-rs/rtic/master/book/en/src/RTIC.svg"
|
||||||
)]
|
)]
|
||||||
//deny_warnings_placeholder_for_ci
|
|
||||||
|
|
||||||
macro_rules! with_backend {
|
macro_rules! with_backend {
|
||||||
(mod: [$($mod:tt),*]) => {
|
(mod: [$($mod:tt),*]) => {
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
//deny_warnings_placeholder_for_ci
|
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
#![feature(async_fn_in_trait)]
|
#![feature(async_fn_in_trait)]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
//deny_warnings_placeholder_for_ci
|
|
||||||
|
|
||||||
pub mod arbiter;
|
pub mod arbiter;
|
||||||
pub mod channel;
|
pub mod channel;
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
//deny_warnings_placeholder_for_ci
|
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
#![feature(async_fn_in_trait)]
|
#![feature(async_fn_in_trait)]
|
||||||
|
|
||||||
|
|
10
rtic/.cargo/config.toml
Normal file
10
rtic/.cargo/config.toml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[target.thumbv6m-none-eabi]
|
||||||
|
runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
|
||||||
|
|
||||||
|
[target.thumbv7m-none-eabi]
|
||||||
|
runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
|
||||||
|
|
||||||
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
|
rustflags = [
|
||||||
|
"-C", "link-arg=-Tlink.x",
|
||||||
|
]
|
|
@ -66,8 +66,7 @@ pub unsafe fn lock<T, R>(
|
||||||
f: impl FnOnce(&mut T) -> R,
|
f: impl FnOnce(&mut T) -> R,
|
||||||
) -> R {
|
) -> R {
|
||||||
if ceiling == (1 << nvic_prio_bits) {
|
if ceiling == (1 << nvic_prio_bits) {
|
||||||
let r = critical_section::with(|_| f(&mut *ptr));
|
critical_section::with(|_| f(&mut *ptr))
|
||||||
r
|
|
||||||
} else {
|
} else {
|
||||||
let current = basepri::read();
|
let current = basepri::read();
|
||||||
basepri::write(cortex_logical2hw(ceiling, nvic_prio_bits));
|
basepri::write(cortex_logical2hw(ceiling, nvic_prio_bits));
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
html_logo_url = "https://raw.githubusercontent.com/rtic-rs/rtic/master/book/en/src/RTIC.svg",
|
html_logo_url = "https://raw.githubusercontent.com/rtic-rs/rtic/master/book/en/src/RTIC.svg",
|
||||||
html_favicon_url = "https://raw.githubusercontent.com/rtic-rs/rtic/master/book/en/src/RTIC.svg"
|
html_favicon_url = "https://raw.githubusercontent.com/rtic-rs/rtic/master/book/en/src/RTIC.svg"
|
||||||
)]
|
)]
|
||||||
//deny_warnings_placeholder_for_ci
|
|
||||||
#![allow(clippy::inline_always)]
|
#![allow(clippy::inline_always)]
|
||||||
|
|
||||||
pub use rtic_core::{prelude as mutex_prelude, Exclusive, Mutex};
|
pub use rtic_core::{prelude as mutex_prelude, Exclusive, Mutex};
|
||||||
|
|
|
@ -9,7 +9,7 @@ mod app {
|
||||||
struct Local {}
|
struct Local {}
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init(cx: init::Context) -> (Shared, Local) {
|
fn init(_cx: init::Context) -> (Shared, Local) {
|
||||||
(Shared {}, Local {})
|
(Shared {}, Local {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,3 @@
|
||||||
warning: unused variable: `cx`
|
|
||||||
--> ui/task-priority-too-high.rs:12:13
|
|
||||||
|
|
|
||||||
12 | fn init(cx: init::Context) -> (Shared, Local) {
|
|
||||||
| ^^ help: if this is intentional, prefix it with an underscore: `_cx`
|
|
||||||
|
|
|
||||||
= note: `#[warn(unused_variables)]` on by default
|
|
||||||
|
|
||||||
error[E0080]: evaluation of constant value failed
|
error[E0080]: evaluation of constant value failed
|
||||||
--> ui/task-priority-too-high.rs:3:1
|
--> ui/task-priority-too-high.rs:3:1
|
||||||
|
|
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{command::CargoCommand, Target, ARMV6M, ARMV7M, ARMV8MBASE, ARMV8MMAIN};
|
use crate::{cargo_command::CargoCommand, Target, ARMV6M, ARMV7M, ARMV8MBASE, ARMV8MMAIN};
|
||||||
use clap::{Args, Parser, Subcommand};
|
use clap::{Args, Parser, Subcommand};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
|
@ -19,15 +19,17 @@ impl fmt::Display for Package {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Package {
|
impl Package {
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> String {
|
||||||
match self {
|
let name = match self {
|
||||||
Package::Rtic => "rtic",
|
Package::Rtic => "rtic",
|
||||||
Package::RticCommon => "rtic-common",
|
Package::RticCommon => "rtic-common",
|
||||||
Package::RticMacros => "rtic-macros",
|
Package::RticMacros => "rtic-macros",
|
||||||
Package::RticMonotonics => "rtic-monotonics",
|
Package::RticMonotonics => "rtic-monotonics",
|
||||||
Package::RticSync => "rtic-sync",
|
Package::RticSync => "rtic-sync",
|
||||||
Package::RticTime => "rtic-time",
|
Package::RticTime => "rtic-time",
|
||||||
}
|
};
|
||||||
|
|
||||||
|
name.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all() -> Vec<Self> {
|
pub fn all() -> Vec<Self> {
|
||||||
|
@ -102,35 +104,41 @@ impl TestMetadata {
|
||||||
);
|
);
|
||||||
let features = Some(backend.to_target().and_features(&features));
|
let features = Some(backend.to_target().and_features(&features));
|
||||||
CargoCommand::Test {
|
CargoCommand::Test {
|
||||||
package: Some(package),
|
package: Some(package.name()),
|
||||||
features,
|
features,
|
||||||
test: Some("ui".to_owned()),
|
test: Some("ui".to_owned()),
|
||||||
|
deny_warnings: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Package::RticMacros => CargoCommand::Test {
|
Package::RticMacros => CargoCommand::Test {
|
||||||
package: Some(package),
|
package: Some(package.name()),
|
||||||
features: Some(backend.to_rtic_macros_feature().to_owned()),
|
features: Some(backend.to_rtic_macros_feature().to_owned()),
|
||||||
test: None,
|
test: None,
|
||||||
|
deny_warnings: true,
|
||||||
},
|
},
|
||||||
Package::RticSync => CargoCommand::Test {
|
Package::RticSync => CargoCommand::Test {
|
||||||
package: Some(package),
|
package: Some(package.name()),
|
||||||
features: Some("testing".to_owned()),
|
features: Some("testing".to_owned()),
|
||||||
test: None,
|
test: None,
|
||||||
|
deny_warnings: true,
|
||||||
},
|
},
|
||||||
Package::RticCommon => CargoCommand::Test {
|
Package::RticCommon => CargoCommand::Test {
|
||||||
package: Some(package),
|
package: Some(package.name()),
|
||||||
features: Some("testing".to_owned()),
|
features: Some("testing".to_owned()),
|
||||||
test: None,
|
test: None,
|
||||||
|
deny_warnings: true,
|
||||||
},
|
},
|
||||||
Package::RticMonotonics => CargoCommand::Test {
|
Package::RticMonotonics => CargoCommand::Test {
|
||||||
package: Some(package),
|
package: Some(package.name()),
|
||||||
features: None,
|
features: None,
|
||||||
test: None,
|
test: None,
|
||||||
|
deny_warnings: true,
|
||||||
},
|
},
|
||||||
Package::RticTime => CargoCommand::Test {
|
Package::RticTime => CargoCommand::Test {
|
||||||
package: Some(package),
|
package: Some(package.name()),
|
||||||
features: Some("critical-section/std".into()),
|
features: Some("critical-section/std".into()),
|
||||||
test: None,
|
test: None,
|
||||||
|
deny_warnings: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,8 +198,12 @@ pub enum BuildOrCheck {
|
||||||
|
|
||||||
#[derive(Parser, Clone)]
|
#[derive(Parser, Clone)]
|
||||||
pub struct Globals {
|
pub struct Globals {
|
||||||
/// For which backend to build (defaults to thumbv7)
|
/// Error out on warnings
|
||||||
#[arg(value_enum, short, long, global = true)]
|
#[arg(short = 'D', long)]
|
||||||
|
pub deny_warnings: bool,
|
||||||
|
|
||||||
|
/// For which backend to build.
|
||||||
|
#[arg(value_enum, short, default_value = "thumbv7", long, global = true)]
|
||||||
pub backend: Option<Backends>,
|
pub backend: Option<Backends>,
|
||||||
|
|
||||||
/// List of comma separated examples to include, all others are excluded
|
/// List of comma separated examples to include, all others are excluded
|
||||||
|
@ -300,6 +312,55 @@ pub enum Commands {
|
||||||
|
|
||||||
/// Build books with mdbook
|
/// Build books with mdbook
|
||||||
Book(Arg),
|
Book(Arg),
|
||||||
|
|
||||||
|
/// Check one or more usage examples.
|
||||||
|
///
|
||||||
|
/// Usage examples are located in ./examples
|
||||||
|
UsageExampleCheck(UsageExamplesOpt),
|
||||||
|
|
||||||
|
/// Build one or more usage examples.
|
||||||
|
///
|
||||||
|
/// Usage examples are located in ./examples
|
||||||
|
#[clap(alias = "./examples")]
|
||||||
|
UsageExampleBuild(UsageExamplesOpt),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Clone, Debug)]
|
||||||
|
pub struct UsageExamplesOpt {
|
||||||
|
/// The usage examples to build. All usage examples are selected if this argument is not provided.
|
||||||
|
///
|
||||||
|
/// Example: `rp2040_local_i2c_init,stm32f3_blinky`.
|
||||||
|
examples: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsageExamplesOpt {
|
||||||
|
pub fn examples(&self) -> anyhow::Result<Vec<String>> {
|
||||||
|
let usage_examples: Vec<_> = std::fs::read_dir("./examples")?
|
||||||
|
.filter_map(Result::ok)
|
||||||
|
.filter(|p| p.metadata().ok().map(|p| p.is_dir()).unwrap_or(false))
|
||||||
|
.filter_map(|p| p.file_name().to_str().map(ToString::to_string))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let selected_examples: Option<Vec<String>> = self
|
||||||
|
.examples
|
||||||
|
.clone()
|
||||||
|
.map(|s| s.split(",").map(ToString::to_string).collect());
|
||||||
|
|
||||||
|
if let Some(selected_examples) = selected_examples {
|
||||||
|
if let Some(unfound_example) = selected_examples
|
||||||
|
.iter()
|
||||||
|
.find(|e| !usage_examples.contains(e))
|
||||||
|
{
|
||||||
|
Err(anyhow::anyhow!(
|
||||||
|
"Usage example {unfound_example} does not exist"
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(selected_examples)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(usage_examples)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args, Debug, Clone)]
|
#[derive(Args, Debug, Clone)]
|
||||||
|
|
750
xtask/src/cargo_command.rs
Normal file
750
xtask/src/cargo_command.rs
Normal file
|
@ -0,0 +1,750 @@
|
||||||
|
use crate::{ExtraArguments, Target};
|
||||||
|
use core::fmt;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub enum BuildMode {
|
||||||
|
Release,
|
||||||
|
Debug,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum CargoCommand<'a> {
|
||||||
|
// For future embedded-ci
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Run {
|
||||||
|
cargoarg: &'a Option<&'a str>,
|
||||||
|
example: &'a str,
|
||||||
|
target: Option<Target<'a>>,
|
||||||
|
features: Option<String>,
|
||||||
|
mode: BuildMode,
|
||||||
|
dir: Option<PathBuf>,
|
||||||
|
},
|
||||||
|
Qemu {
|
||||||
|
cargoarg: &'a Option<&'a str>,
|
||||||
|
example: &'a str,
|
||||||
|
target: Option<Target<'a>>,
|
||||||
|
features: Option<String>,
|
||||||
|
mode: BuildMode,
|
||||||
|
dir: Option<PathBuf>,
|
||||||
|
deny_warnings: bool,
|
||||||
|
},
|
||||||
|
ExampleBuild {
|
||||||
|
cargoarg: &'a Option<&'a str>,
|
||||||
|
example: &'a str,
|
||||||
|
target: Option<Target<'a>>,
|
||||||
|
features: Option<String>,
|
||||||
|
mode: BuildMode,
|
||||||
|
dir: Option<PathBuf>,
|
||||||
|
deny_warnings: bool,
|
||||||
|
},
|
||||||
|
ExampleCheck {
|
||||||
|
cargoarg: &'a Option<&'a str>,
|
||||||
|
example: &'a str,
|
||||||
|
target: Option<Target<'a>>,
|
||||||
|
features: Option<String>,
|
||||||
|
mode: BuildMode,
|
||||||
|
deny_warnings: bool,
|
||||||
|
},
|
||||||
|
Build {
|
||||||
|
cargoarg: &'a Option<&'a str>,
|
||||||
|
package: Option<String>,
|
||||||
|
target: Option<Target<'a>>,
|
||||||
|
features: Option<String>,
|
||||||
|
mode: BuildMode,
|
||||||
|
dir: Option<PathBuf>,
|
||||||
|
deny_warnings: bool,
|
||||||
|
},
|
||||||
|
Check {
|
||||||
|
cargoarg: &'a Option<&'a str>,
|
||||||
|
package: Option<String>,
|
||||||
|
target: Option<Target<'a>>,
|
||||||
|
features: Option<String>,
|
||||||
|
mode: BuildMode,
|
||||||
|
dir: Option<PathBuf>,
|
||||||
|
deny_warnings: bool,
|
||||||
|
},
|
||||||
|
Clippy {
|
||||||
|
cargoarg: &'a Option<&'a str>,
|
||||||
|
package: Option<String>,
|
||||||
|
target: Option<Target<'a>>,
|
||||||
|
features: Option<String>,
|
||||||
|
deny_warnings: bool,
|
||||||
|
},
|
||||||
|
Format {
|
||||||
|
cargoarg: &'a Option<&'a str>,
|
||||||
|
package: Option<String>,
|
||||||
|
check_only: bool,
|
||||||
|
},
|
||||||
|
Doc {
|
||||||
|
cargoarg: &'a Option<&'a str>,
|
||||||
|
features: Option<String>,
|
||||||
|
arguments: Option<ExtraArguments>,
|
||||||
|
deny_warnings: bool,
|
||||||
|
},
|
||||||
|
Test {
|
||||||
|
package: Option<String>,
|
||||||
|
features: Option<String>,
|
||||||
|
test: Option<String>,
|
||||||
|
deny_warnings: bool,
|
||||||
|
},
|
||||||
|
Book {
|
||||||
|
arguments: Option<ExtraArguments>,
|
||||||
|
},
|
||||||
|
ExampleSize {
|
||||||
|
cargoarg: &'a Option<&'a str>,
|
||||||
|
example: &'a str,
|
||||||
|
target: Option<Target<'a>>,
|
||||||
|
features: Option<String>,
|
||||||
|
mode: BuildMode,
|
||||||
|
arguments: Option<ExtraArguments>,
|
||||||
|
dir: Option<PathBuf>,
|
||||||
|
deny_warnings: bool,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Display for CargoCommand<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fn p(p: &Option<String>) -> String {
|
||||||
|
if let Some(package) = p {
|
||||||
|
format!("package {package}")
|
||||||
|
} else {
|
||||||
|
format!("default package")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn feat(f: &Option<String>) -> String {
|
||||||
|
if let Some(features) = f {
|
||||||
|
format!("\"{features}\"")
|
||||||
|
} else {
|
||||||
|
format!("no features")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn carg(f: &&Option<&str>) -> String {
|
||||||
|
if let Some(cargoarg) = f {
|
||||||
|
format!("{cargoarg}")
|
||||||
|
} else {
|
||||||
|
format!("no cargo args")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn details(
|
||||||
|
deny_warnings: bool,
|
||||||
|
target: &Option<Target>,
|
||||||
|
mode: Option<&BuildMode>,
|
||||||
|
features: &Option<String>,
|
||||||
|
cargoarg: &&Option<&str>,
|
||||||
|
path: Option<&PathBuf>,
|
||||||
|
) -> String {
|
||||||
|
let feat = feat(features);
|
||||||
|
let carg = carg(cargoarg);
|
||||||
|
let in_dir = if let Some(path) = path {
|
||||||
|
let path = path.to_str().unwrap_or("<can't display>");
|
||||||
|
format!("in {path}")
|
||||||
|
} else {
|
||||||
|
format!("")
|
||||||
|
};
|
||||||
|
|
||||||
|
let target = if let Some(target) = target {
|
||||||
|
format!("{target}")
|
||||||
|
} else {
|
||||||
|
format!("<no explicit target>")
|
||||||
|
};
|
||||||
|
|
||||||
|
let mode = if let Some(mode) = mode {
|
||||||
|
format!("{mode}")
|
||||||
|
} else {
|
||||||
|
format!("debug")
|
||||||
|
};
|
||||||
|
|
||||||
|
let deny_warnings = if deny_warnings {
|
||||||
|
format!("deny warnings, ")
|
||||||
|
} else {
|
||||||
|
format!("")
|
||||||
|
};
|
||||||
|
|
||||||
|
if cargoarg.is_some() && path.is_some() {
|
||||||
|
format!("({deny_warnings}{target}, {mode}, {feat}, {carg}, {in_dir})")
|
||||||
|
} else if cargoarg.is_some() {
|
||||||
|
format!("({deny_warnings}{target}, {mode}, {feat}, {carg})")
|
||||||
|
} else if path.is_some() {
|
||||||
|
format!("({deny_warnings}{target}, {mode}, {feat}, {in_dir})")
|
||||||
|
} else {
|
||||||
|
format!("({deny_warnings}{target}, {mode}, {feat})")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match self {
|
||||||
|
CargoCommand::Run {
|
||||||
|
cargoarg,
|
||||||
|
example,
|
||||||
|
target,
|
||||||
|
features,
|
||||||
|
mode,
|
||||||
|
dir,
|
||||||
|
} => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Run example {example} {}",
|
||||||
|
details(false, target, Some(mode), features, cargoarg, dir.as_ref())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
CargoCommand::Qemu {
|
||||||
|
cargoarg,
|
||||||
|
example,
|
||||||
|
target,
|
||||||
|
features,
|
||||||
|
mode,
|
||||||
|
dir,
|
||||||
|
deny_warnings,
|
||||||
|
} => {
|
||||||
|
let warns = *deny_warnings;
|
||||||
|
let details = details(warns, target, Some(mode), features, cargoarg, dir.as_ref());
|
||||||
|
write!(f, "Run example {example} in QEMU {details}",)
|
||||||
|
}
|
||||||
|
CargoCommand::ExampleBuild {
|
||||||
|
cargoarg,
|
||||||
|
example,
|
||||||
|
target,
|
||||||
|
features,
|
||||||
|
mode,
|
||||||
|
dir,
|
||||||
|
deny_warnings,
|
||||||
|
} => {
|
||||||
|
let warns = *deny_warnings;
|
||||||
|
let details = details(warns, target, Some(mode), features, cargoarg, dir.as_ref());
|
||||||
|
write!(f, "Build example {example} {details}",)
|
||||||
|
}
|
||||||
|
CargoCommand::ExampleCheck {
|
||||||
|
cargoarg,
|
||||||
|
example,
|
||||||
|
target,
|
||||||
|
features,
|
||||||
|
mode,
|
||||||
|
deny_warnings,
|
||||||
|
} => write!(
|
||||||
|
f,
|
||||||
|
"Check example {example} {}",
|
||||||
|
details(*deny_warnings, target, Some(mode), features, cargoarg, None)
|
||||||
|
),
|
||||||
|
CargoCommand::Build {
|
||||||
|
cargoarg,
|
||||||
|
package,
|
||||||
|
target,
|
||||||
|
features,
|
||||||
|
mode,
|
||||||
|
dir,
|
||||||
|
deny_warnings,
|
||||||
|
} => {
|
||||||
|
let package = p(package);
|
||||||
|
let warns = *deny_warnings;
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Build {package} {}",
|
||||||
|
details(warns, target, Some(mode), features, cargoarg, dir.as_ref())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
CargoCommand::Check {
|
||||||
|
cargoarg,
|
||||||
|
package,
|
||||||
|
target,
|
||||||
|
features,
|
||||||
|
mode,
|
||||||
|
dir,
|
||||||
|
deny_warnings,
|
||||||
|
} => {
|
||||||
|
let package = p(package);
|
||||||
|
let warns = *deny_warnings;
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Check {package} {}",
|
||||||
|
details(warns, target, Some(mode), features, cargoarg, dir.as_ref())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
CargoCommand::Clippy {
|
||||||
|
cargoarg,
|
||||||
|
package,
|
||||||
|
target,
|
||||||
|
features,
|
||||||
|
deny_warnings,
|
||||||
|
} => {
|
||||||
|
let details = details(*deny_warnings, target, None, features, cargoarg, None);
|
||||||
|
let package = p(package);
|
||||||
|
write!(f, "Clippy {package} {details}")
|
||||||
|
}
|
||||||
|
CargoCommand::Format {
|
||||||
|
cargoarg,
|
||||||
|
package,
|
||||||
|
check_only,
|
||||||
|
} => {
|
||||||
|
let package = p(package);
|
||||||
|
let carg = carg(cargoarg);
|
||||||
|
|
||||||
|
let carg = if cargoarg.is_some() {
|
||||||
|
format!("(cargo args: {carg})")
|
||||||
|
} else {
|
||||||
|
format!("")
|
||||||
|
};
|
||||||
|
|
||||||
|
if *check_only {
|
||||||
|
write!(f, "Check format for {package} {carg}")
|
||||||
|
} else {
|
||||||
|
write!(f, "Format {package} {carg}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CargoCommand::Doc {
|
||||||
|
cargoarg,
|
||||||
|
features,
|
||||||
|
arguments,
|
||||||
|
deny_warnings,
|
||||||
|
} => {
|
||||||
|
let feat = feat(features);
|
||||||
|
let carg = carg(cargoarg);
|
||||||
|
let arguments = arguments
|
||||||
|
.clone()
|
||||||
|
.map(|a| format!("{a}"))
|
||||||
|
.unwrap_or_else(|| "no extra arguments".into());
|
||||||
|
let deny_warnings = if *deny_warnings {
|
||||||
|
format!("deny warnings, ")
|
||||||
|
} else {
|
||||||
|
format!("")
|
||||||
|
};
|
||||||
|
if cargoarg.is_some() {
|
||||||
|
write!(f, "Document ({deny_warnings}{feat}, {carg}, {arguments})")
|
||||||
|
} else {
|
||||||
|
write!(f, "Document ({deny_warnings}{feat}, {arguments})")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CargoCommand::Test {
|
||||||
|
package,
|
||||||
|
features,
|
||||||
|
test,
|
||||||
|
deny_warnings,
|
||||||
|
} => {
|
||||||
|
let p = p(package);
|
||||||
|
let test = test
|
||||||
|
.clone()
|
||||||
|
.map(|t| format!("test {t}"))
|
||||||
|
.unwrap_or("all tests".into());
|
||||||
|
let deny_warnings = if *deny_warnings {
|
||||||
|
format!("deny warnings, ")
|
||||||
|
} else {
|
||||||
|
format!("")
|
||||||
|
};
|
||||||
|
let feat = feat(features);
|
||||||
|
write!(f, "Run {test} in {p} ({deny_warnings}features: {feat})")
|
||||||
|
}
|
||||||
|
CargoCommand::Book { arguments: _ } => write!(f, "Build the book"),
|
||||||
|
CargoCommand::ExampleSize {
|
||||||
|
cargoarg,
|
||||||
|
example,
|
||||||
|
target,
|
||||||
|
features,
|
||||||
|
mode,
|
||||||
|
arguments: _,
|
||||||
|
dir,
|
||||||
|
deny_warnings,
|
||||||
|
} => {
|
||||||
|
let warns = *deny_warnings;
|
||||||
|
let details = details(warns, target, Some(mode), features, cargoarg, dir.as_ref());
|
||||||
|
write!(f, "Compute size of example {example} {details}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CargoCommand<'a> {
|
||||||
|
pub fn as_cmd_string(&self) -> String {
|
||||||
|
let env = if let Some((key, value)) = self.extra_env() {
|
||||||
|
format!("{key}=\"{value}\" ")
|
||||||
|
} else {
|
||||||
|
format!("")
|
||||||
|
};
|
||||||
|
|
||||||
|
let cd = if let Some(Some(chdir)) = self.chdir().map(|p| p.to_str()) {
|
||||||
|
format!("cd {chdir} && ")
|
||||||
|
} else {
|
||||||
|
format!("")
|
||||||
|
};
|
||||||
|
|
||||||
|
let executable = self.executable();
|
||||||
|
let args = self.args().join(" ");
|
||||||
|
format!("{env}{cd}{executable} {args}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn command(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
CargoCommand::Run { .. } | CargoCommand::Qemu { .. } => "run",
|
||||||
|
CargoCommand::ExampleCheck { .. } | CargoCommand::Check { .. } => "check",
|
||||||
|
CargoCommand::ExampleBuild { .. } | CargoCommand::Build { .. } => "build",
|
||||||
|
CargoCommand::ExampleSize { .. } => "size",
|
||||||
|
CargoCommand::Clippy { .. } => "clippy",
|
||||||
|
CargoCommand::Format { .. } => "fmt",
|
||||||
|
CargoCommand::Doc { .. } => "doc",
|
||||||
|
CargoCommand::Book { .. } => "build",
|
||||||
|
CargoCommand::Test { .. } => "test",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn executable(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
CargoCommand::Run { .. }
|
||||||
|
| CargoCommand::Qemu { .. }
|
||||||
|
| CargoCommand::ExampleCheck { .. }
|
||||||
|
| CargoCommand::Check { .. }
|
||||||
|
| CargoCommand::ExampleBuild { .. }
|
||||||
|
| CargoCommand::Build { .. }
|
||||||
|
| CargoCommand::ExampleSize { .. }
|
||||||
|
| CargoCommand::Clippy { .. }
|
||||||
|
| CargoCommand::Format { .. }
|
||||||
|
| CargoCommand::Test { .. }
|
||||||
|
| CargoCommand::Doc { .. } => "cargo",
|
||||||
|
CargoCommand::Book { .. } => "mdbook",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build args using common arguments for all commands, and the
|
||||||
|
/// specific information provided
|
||||||
|
fn build_args<'i, T: Iterator<Item = &'i str>>(
|
||||||
|
&'i self,
|
||||||
|
nightly: bool,
|
||||||
|
cargoarg: &'i Option<&'i str>,
|
||||||
|
features: &'i Option<String>,
|
||||||
|
mode: Option<&'i BuildMode>,
|
||||||
|
extra: T,
|
||||||
|
) -> Vec<&str> {
|
||||||
|
let mut args: Vec<&str> = Vec::new();
|
||||||
|
|
||||||
|
if nightly {
|
||||||
|
args.push("+nightly");
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(cargoarg) = cargoarg.as_deref() {
|
||||||
|
args.push(cargoarg);
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push(self.command());
|
||||||
|
|
||||||
|
if let Some(target) = self.target() {
|
||||||
|
args.extend_from_slice(&["--target", target.triple()])
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(features) = features.as_ref() {
|
||||||
|
args.extend_from_slice(&["--features", features]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(mode) = mode.map(|m| m.to_flag()).flatten() {
|
||||||
|
args.push(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
args.extend(extra);
|
||||||
|
|
||||||
|
args
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Turn the ExtraArguments into an interator that contains the separating dashes
|
||||||
|
/// and the rest of the arguments.
|
||||||
|
///
|
||||||
|
/// NOTE: you _must_ chain this iterator at the _end_ of the extra arguments.
|
||||||
|
fn extra_args(args: Option<&ExtraArguments>) -> impl Iterator<Item = &str> {
|
||||||
|
#[allow(irrefutable_let_patterns)]
|
||||||
|
let args = if let Some(ExtraArguments::Other(arguments)) = args {
|
||||||
|
// Extra arguments must be passed after "--"
|
||||||
|
["--"]
|
||||||
|
.into_iter()
|
||||||
|
.chain(arguments.iter().map(String::as_str))
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
args.into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn args(&self) -> Vec<&str> {
|
||||||
|
fn p(package: &Option<String>) -> impl Iterator<Item = &str> {
|
||||||
|
if let Some(package) = package {
|
||||||
|
vec!["--package", &package].into_iter()
|
||||||
|
} else {
|
||||||
|
vec![].into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match self {
|
||||||
|
// For future embedded-ci, for now the same as Qemu
|
||||||
|
CargoCommand::Run {
|
||||||
|
cargoarg,
|
||||||
|
example,
|
||||||
|
features,
|
||||||
|
mode,
|
||||||
|
// dir is exposed through `chdir`
|
||||||
|
dir: _,
|
||||||
|
// Target is added by build_args
|
||||||
|
target: _,
|
||||||
|
} => self.build_args(
|
||||||
|
true,
|
||||||
|
cargoarg,
|
||||||
|
features,
|
||||||
|
Some(mode),
|
||||||
|
["--example", example].into_iter(),
|
||||||
|
),
|
||||||
|
CargoCommand::Qemu {
|
||||||
|
cargoarg,
|
||||||
|
example,
|
||||||
|
features,
|
||||||
|
mode,
|
||||||
|
// dir is exposed through `chdir`
|
||||||
|
dir: _,
|
||||||
|
// Target is added by build_args
|
||||||
|
target: _,
|
||||||
|
// deny_warnings is exposed through `extra_env`
|
||||||
|
deny_warnings: _,
|
||||||
|
} => self.build_args(
|
||||||
|
true,
|
||||||
|
cargoarg,
|
||||||
|
features,
|
||||||
|
Some(mode),
|
||||||
|
["--example", example].into_iter(),
|
||||||
|
),
|
||||||
|
CargoCommand::Build {
|
||||||
|
cargoarg,
|
||||||
|
package,
|
||||||
|
features,
|
||||||
|
mode,
|
||||||
|
// Target is added by build_args
|
||||||
|
target: _,
|
||||||
|
// Dir is exposed through `chdir`
|
||||||
|
dir: _,
|
||||||
|
// deny_warnings is exposed through `extra_env`
|
||||||
|
deny_warnings: _,
|
||||||
|
} => self.build_args(true, cargoarg, features, Some(mode), p(package)),
|
||||||
|
CargoCommand::Check {
|
||||||
|
cargoarg,
|
||||||
|
package,
|
||||||
|
features,
|
||||||
|
mode,
|
||||||
|
// Dir is exposed through `chdir`
|
||||||
|
dir: _,
|
||||||
|
// Target is added by build_args
|
||||||
|
target: _,
|
||||||
|
// deny_warnings is exposed through `extra_env`
|
||||||
|
deny_warnings: _,
|
||||||
|
} => self.build_args(true, cargoarg, features, Some(mode), p(package)),
|
||||||
|
CargoCommand::Clippy {
|
||||||
|
cargoarg,
|
||||||
|
package,
|
||||||
|
features,
|
||||||
|
// Target is added by build_args
|
||||||
|
target: _,
|
||||||
|
deny_warnings,
|
||||||
|
} => {
|
||||||
|
let deny_warnings = if *deny_warnings {
|
||||||
|
vec!["--", "-D", "warnings"]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
|
let extra = p(package).chain(deny_warnings);
|
||||||
|
self.build_args(true, cargoarg, features, None, extra)
|
||||||
|
}
|
||||||
|
CargoCommand::Doc {
|
||||||
|
cargoarg,
|
||||||
|
features,
|
||||||
|
arguments,
|
||||||
|
// deny_warnings is exposed through `extra_env`
|
||||||
|
deny_warnings: _,
|
||||||
|
} => {
|
||||||
|
let extra = Self::extra_args(arguments.as_ref());
|
||||||
|
self.build_args(true, cargoarg, features, None, extra)
|
||||||
|
}
|
||||||
|
CargoCommand::Test {
|
||||||
|
package,
|
||||||
|
features,
|
||||||
|
test,
|
||||||
|
// deny_warnings is exposed through `extra_env`
|
||||||
|
deny_warnings: _,
|
||||||
|
} => {
|
||||||
|
let extra = if let Some(test) = test {
|
||||||
|
vec!["--test", test]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
let package = p(package);
|
||||||
|
let extra = extra.into_iter().chain(package);
|
||||||
|
self.build_args(true, &None, features, None, extra)
|
||||||
|
}
|
||||||
|
CargoCommand::Book { arguments } => {
|
||||||
|
let mut args = vec![];
|
||||||
|
|
||||||
|
if let Some(ExtraArguments::Other(arguments)) = arguments {
|
||||||
|
for arg in arguments {
|
||||||
|
args.extend_from_slice(&[arg.as_str()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If no argument given, run mdbook build
|
||||||
|
// with default path to book
|
||||||
|
args.extend_from_slice(&[self.command()]);
|
||||||
|
args.extend_from_slice(&["book/en"]);
|
||||||
|
}
|
||||||
|
args
|
||||||
|
}
|
||||||
|
CargoCommand::Format {
|
||||||
|
cargoarg,
|
||||||
|
package,
|
||||||
|
check_only,
|
||||||
|
} => {
|
||||||
|
let extra = if *check_only { Some("--check") } else { None };
|
||||||
|
let package = p(package);
|
||||||
|
self.build_args(
|
||||||
|
true,
|
||||||
|
cargoarg,
|
||||||
|
&None,
|
||||||
|
None,
|
||||||
|
extra.into_iter().chain(package),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
CargoCommand::ExampleBuild {
|
||||||
|
cargoarg,
|
||||||
|
example,
|
||||||
|
features,
|
||||||
|
mode,
|
||||||
|
// dir is exposed through `chdir`
|
||||||
|
dir: _,
|
||||||
|
// Target is added by build_args
|
||||||
|
target: _,
|
||||||
|
// deny_warnings is exposed through `extra_env`
|
||||||
|
deny_warnings: _,
|
||||||
|
} => self.build_args(
|
||||||
|
true,
|
||||||
|
cargoarg,
|
||||||
|
features,
|
||||||
|
Some(mode),
|
||||||
|
["--example", example].into_iter(),
|
||||||
|
),
|
||||||
|
CargoCommand::ExampleCheck {
|
||||||
|
cargoarg,
|
||||||
|
example,
|
||||||
|
features,
|
||||||
|
mode,
|
||||||
|
// Target is added by build_args
|
||||||
|
target: _,
|
||||||
|
// deny_warnings is exposed through `extra_env`
|
||||||
|
deny_warnings: _,
|
||||||
|
} => self.build_args(
|
||||||
|
true,
|
||||||
|
cargoarg,
|
||||||
|
features,
|
||||||
|
Some(mode),
|
||||||
|
["--example", example].into_iter(),
|
||||||
|
),
|
||||||
|
CargoCommand::ExampleSize {
|
||||||
|
cargoarg,
|
||||||
|
example,
|
||||||
|
features,
|
||||||
|
mode,
|
||||||
|
arguments,
|
||||||
|
// Target is added by build_args
|
||||||
|
target: _,
|
||||||
|
// dir is exposed through `chdir`
|
||||||
|
dir: _,
|
||||||
|
// deny_warnings is exposed through `extra_env`
|
||||||
|
deny_warnings: _,
|
||||||
|
} => {
|
||||||
|
let extra = ["--example", example]
|
||||||
|
.into_iter()
|
||||||
|
.chain(Self::extra_args(arguments.as_ref()));
|
||||||
|
|
||||||
|
self.build_args(true, cargoarg, features, Some(mode), extra)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TODO: integrate this into `args` once `-C` becomes stable.
|
||||||
|
pub fn chdir(&self) -> Option<&PathBuf> {
|
||||||
|
match self {
|
||||||
|
CargoCommand::Qemu { dir, .. }
|
||||||
|
| CargoCommand::ExampleBuild { dir, .. }
|
||||||
|
| CargoCommand::ExampleSize { dir, .. }
|
||||||
|
| CargoCommand::Build { dir, .. }
|
||||||
|
| CargoCommand::Run { dir, .. }
|
||||||
|
| CargoCommand::Check { dir, .. } => dir.as_ref(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn target(&self) -> Option<&Target> {
|
||||||
|
match self {
|
||||||
|
CargoCommand::Run { target, .. }
|
||||||
|
| CargoCommand::Qemu { target, .. }
|
||||||
|
| CargoCommand::ExampleBuild { target, .. }
|
||||||
|
| CargoCommand::ExampleCheck { target, .. }
|
||||||
|
| CargoCommand::Build { target, .. }
|
||||||
|
| CargoCommand::Check { target, .. }
|
||||||
|
| CargoCommand::Clippy { target, .. }
|
||||||
|
| CargoCommand::ExampleSize { target, .. } => target.as_ref(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extra_env(&self) -> Option<(&str, &str)> {
|
||||||
|
match self {
|
||||||
|
// Clippy is a special case: it sets deny warnings
|
||||||
|
// through an argument to rustc.
|
||||||
|
CargoCommand::Clippy { .. } => None,
|
||||||
|
CargoCommand::Doc { .. } => Some(("RUSTDOCFLAGS", "-D warnings")),
|
||||||
|
|
||||||
|
CargoCommand::Qemu { deny_warnings, .. }
|
||||||
|
| CargoCommand::ExampleBuild { deny_warnings, .. }
|
||||||
|
| CargoCommand::ExampleSize { deny_warnings, .. } => {
|
||||||
|
if *deny_warnings {
|
||||||
|
// NOTE: this also needs the link-arg because .cargo/config.toml
|
||||||
|
// is ignored if you set the RUSTFLAGS env variable.
|
||||||
|
Some(("RUSTFLAGS", "-D warnings -C link-arg=-Tlink.x"))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CargoCommand::Check { deny_warnings, .. }
|
||||||
|
| CargoCommand::ExampleCheck { deny_warnings, .. }
|
||||||
|
| CargoCommand::Build { deny_warnings, .. }
|
||||||
|
| CargoCommand::Test { deny_warnings, .. } => {
|
||||||
|
if *deny_warnings {
|
||||||
|
Some(("RUSTFLAGS", "-D warnings"))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_stdout_intermediate(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::ExampleSize { .. } => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuildMode {
|
||||||
|
#[allow(clippy::wrong_self_convention)]
|
||||||
|
pub fn to_flag(&self) -> Option<&str> {
|
||||||
|
match self {
|
||||||
|
BuildMode::Release => Some("--release"),
|
||||||
|
BuildMode::Debug => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for BuildMode {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let cmd = match self {
|
||||||
|
BuildMode::Release => "release",
|
||||||
|
BuildMode::Debug => "debug",
|
||||||
|
};
|
||||||
|
|
||||||
|
write!(f, "{cmd}")
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,345 +0,0 @@
|
||||||
use crate::{
|
|
||||||
argument_parsing::{Backends, BuildOrCheck, ExtraArguments, Globals, PackageOpt, TestMetadata},
|
|
||||||
command::{BuildMode, CargoCommand},
|
|
||||||
command_parser, RunResult,
|
|
||||||
};
|
|
||||||
use log::error;
|
|
||||||
|
|
||||||
#[cfg(feature = "rayon")]
|
|
||||||
use rayon::prelude::*;
|
|
||||||
|
|
||||||
use iters::*;
|
|
||||||
|
|
||||||
pub enum FinalRunResult<'c> {
|
|
||||||
Success(CargoCommand<'c>, RunResult),
|
|
||||||
Failed(CargoCommand<'c>, RunResult),
|
|
||||||
CommandError(anyhow::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_and_convert<'a>(
|
|
||||||
(global, command, overwrite): (&Globals, CargoCommand<'a>, bool),
|
|
||||||
) -> FinalRunResult<'a> {
|
|
||||||
// Run the command
|
|
||||||
let result = command_parser(global, &command, overwrite);
|
|
||||||
match result {
|
|
||||||
// If running the command succeeded without looking at any of the results,
|
|
||||||
// log the data and see if the actual execution was succesfull too.
|
|
||||||
Ok(result) => {
|
|
||||||
if result.exit_status.success() {
|
|
||||||
FinalRunResult::Success(command, result)
|
|
||||||
} else {
|
|
||||||
FinalRunResult::Failed(command, result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If it didn't and some IO error occured, just panic
|
|
||||||
Err(e) => FinalRunResult::CommandError(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CoalescingRunner<'c> {
|
|
||||||
/// Run all the commands in this iterator, and coalesce the results into
|
|
||||||
/// one error (if any individual commands failed)
|
|
||||||
fn run_and_coalesce(self) -> Vec<FinalRunResult<'c>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "rayon"))]
|
|
||||||
mod iters {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub fn examples_iter(examples: &[String]) -> impl Iterator<Item = &String> {
|
|
||||||
examples.into_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'g, 'c, I> CoalescingRunner<'c> for I
|
|
||||||
where
|
|
||||||
I: Iterator<Item = (&'g Globals, CargoCommand<'c>, bool)>,
|
|
||||||
{
|
|
||||||
fn run_and_coalesce(self) -> Vec<FinalRunResult<'c>> {
|
|
||||||
self.map(run_and_convert).collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "rayon")]
|
|
||||||
mod iters {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub fn examples_iter(examples: &[String]) -> impl ParallelIterator<Item = &String> {
|
|
||||||
examples.into_par_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'g, 'c, I> CoalescingRunner<'c> for I
|
|
||||||
where
|
|
||||||
I: ParallelIterator<Item = (&'g Globals, CargoCommand<'c>, bool)>,
|
|
||||||
{
|
|
||||||
fn run_and_coalesce(self) -> Vec<FinalRunResult<'c>> {
|
|
||||||
self.map(run_and_convert).collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cargo command to either build or check
|
|
||||||
pub fn cargo<'c>(
|
|
||||||
globals: &Globals,
|
|
||||||
operation: BuildOrCheck,
|
|
||||||
cargoarg: &'c Option<&'c str>,
|
|
||||||
package: &'c PackageOpt,
|
|
||||||
backend: Backends,
|
|
||||||
) -> Vec<FinalRunResult<'c>> {
|
|
||||||
let runner = package
|
|
||||||
.packages()
|
|
||||||
.flat_map(|package| {
|
|
||||||
let target = backend.to_target();
|
|
||||||
let features = package.features(target, backend, globals.partial);
|
|
||||||
|
|
||||||
#[cfg(feature = "rayon")]
|
|
||||||
{
|
|
||||||
features.into_par_iter().map(move |f| (package, target, f))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "rayon"))]
|
|
||||||
{
|
|
||||||
features.into_iter().map(move |f| (package, target, f))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(move |(package, target, features)| {
|
|
||||||
let command = match operation {
|
|
||||||
BuildOrCheck::Check => CargoCommand::Check {
|
|
||||||
cargoarg,
|
|
||||||
package: Some(package),
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
mode: BuildMode::Release,
|
|
||||||
},
|
|
||||||
BuildOrCheck::Build => CargoCommand::Build {
|
|
||||||
cargoarg,
|
|
||||||
package: Some(package),
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
mode: BuildMode::Release,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
(globals, command, false)
|
|
||||||
});
|
|
||||||
|
|
||||||
runner.run_and_coalesce()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cargo command to either build or check all examples
|
|
||||||
///
|
|
||||||
/// The examples are in rtic/examples
|
|
||||||
pub fn cargo_example<'c>(
|
|
||||||
globals: &Globals,
|
|
||||||
operation: BuildOrCheck,
|
|
||||||
cargoarg: &'c Option<&'c str>,
|
|
||||||
backend: Backends,
|
|
||||||
examples: &'c [String],
|
|
||||||
) -> Vec<FinalRunResult<'c>> {
|
|
||||||
let runner = examples_iter(examples).map(|example| {
|
|
||||||
let features = Some(backend.to_target().and_features(backend.to_rtic_feature()));
|
|
||||||
|
|
||||||
let command = match operation {
|
|
||||||
BuildOrCheck::Check => CargoCommand::ExampleCheck {
|
|
||||||
cargoarg,
|
|
||||||
example,
|
|
||||||
target: backend.to_target(),
|
|
||||||
features,
|
|
||||||
mode: BuildMode::Release,
|
|
||||||
},
|
|
||||||
BuildOrCheck::Build => CargoCommand::ExampleBuild {
|
|
||||||
cargoarg,
|
|
||||||
example,
|
|
||||||
target: backend.to_target(),
|
|
||||||
features,
|
|
||||||
mode: BuildMode::Release,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
(globals, command, false)
|
|
||||||
});
|
|
||||||
runner.run_and_coalesce()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run cargo clippy on selected package
|
|
||||||
pub fn cargo_clippy<'c>(
|
|
||||||
globals: &Globals,
|
|
||||||
cargoarg: &'c Option<&'c str>,
|
|
||||||
package: &'c PackageOpt,
|
|
||||||
backend: Backends,
|
|
||||||
) -> Vec<FinalRunResult<'c>> {
|
|
||||||
let runner = package
|
|
||||||
.packages()
|
|
||||||
.flat_map(|package| {
|
|
||||||
let target = backend.to_target();
|
|
||||||
let features = package.features(target, backend, globals.partial);
|
|
||||||
|
|
||||||
#[cfg(feature = "rayon")]
|
|
||||||
{
|
|
||||||
features.into_par_iter().map(move |f| (package, target, f))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "rayon"))]
|
|
||||||
{
|
|
||||||
features.into_iter().map(move |f| (package, target, f))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(move |(package, target, features)| {
|
|
||||||
(
|
|
||||||
globals,
|
|
||||||
CargoCommand::Clippy {
|
|
||||||
cargoarg,
|
|
||||||
package: Some(package),
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
runner.run_and_coalesce()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run cargo fmt on selected package
|
|
||||||
pub fn cargo_format<'c>(
|
|
||||||
globals: &Globals,
|
|
||||||
cargoarg: &'c Option<&'c str>,
|
|
||||||
package: &'c PackageOpt,
|
|
||||||
check_only: bool,
|
|
||||||
) -> Vec<FinalRunResult<'c>> {
|
|
||||||
let runner = package.packages().map(|p| {
|
|
||||||
(
|
|
||||||
globals,
|
|
||||||
CargoCommand::Format {
|
|
||||||
cargoarg,
|
|
||||||
package: Some(p),
|
|
||||||
check_only,
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
runner.run_and_coalesce()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run cargo doc
|
|
||||||
pub fn cargo_doc<'c>(
|
|
||||||
globals: &Globals,
|
|
||||||
cargoarg: &'c Option<&'c str>,
|
|
||||||
backend: Backends,
|
|
||||||
arguments: &'c Option<ExtraArguments>,
|
|
||||||
) -> Vec<FinalRunResult<'c>> {
|
|
||||||
let features = Some(backend.to_target().and_features(backend.to_rtic_feature()));
|
|
||||||
|
|
||||||
let command = CargoCommand::Doc {
|
|
||||||
cargoarg,
|
|
||||||
features,
|
|
||||||
arguments: arguments.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
vec![run_and_convert((globals, command, false))]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run cargo test on the selected package or all packages
|
|
||||||
///
|
|
||||||
/// If no package is specified, loop through all packages
|
|
||||||
pub fn cargo_test<'c>(
|
|
||||||
globals: &Globals,
|
|
||||||
package: &'c PackageOpt,
|
|
||||||
backend: Backends,
|
|
||||||
) -> Vec<FinalRunResult<'c>> {
|
|
||||||
package
|
|
||||||
.packages()
|
|
||||||
.map(|p| (globals, TestMetadata::match_package(p, backend), false))
|
|
||||||
.run_and_coalesce()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Use mdbook to build the book
|
|
||||||
pub fn cargo_book<'c>(
|
|
||||||
globals: &Globals,
|
|
||||||
arguments: &'c Option<ExtraArguments>,
|
|
||||||
) -> Vec<FinalRunResult<'c>> {
|
|
||||||
vec![run_and_convert((
|
|
||||||
globals,
|
|
||||||
CargoCommand::Book {
|
|
||||||
arguments: arguments.clone(),
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
))]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run examples
|
|
||||||
///
|
|
||||||
/// Supports updating the expected output via the overwrite argument
|
|
||||||
pub fn run_test<'c>(
|
|
||||||
globals: &Globals,
|
|
||||||
cargoarg: &'c Option<&'c str>,
|
|
||||||
backend: Backends,
|
|
||||||
examples: &'c [String],
|
|
||||||
overwrite: bool,
|
|
||||||
) -> Vec<FinalRunResult<'c>> {
|
|
||||||
let target = backend.to_target();
|
|
||||||
let features = Some(target.and_features(backend.to_rtic_feature()));
|
|
||||||
|
|
||||||
examples_iter(examples)
|
|
||||||
.map(|example| {
|
|
||||||
let cmd = CargoCommand::ExampleBuild {
|
|
||||||
cargoarg: &Some("--quiet"),
|
|
||||||
example,
|
|
||||||
target,
|
|
||||||
features: features.clone(),
|
|
||||||
mode: BuildMode::Release,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(err) = command_parser(globals, &cmd, false) {
|
|
||||||
error!("{err}");
|
|
||||||
}
|
|
||||||
|
|
||||||
let cmd = CargoCommand::Qemu {
|
|
||||||
cargoarg,
|
|
||||||
example,
|
|
||||||
target,
|
|
||||||
features: features.clone(),
|
|
||||||
mode: BuildMode::Release,
|
|
||||||
};
|
|
||||||
|
|
||||||
(globals, cmd, overwrite)
|
|
||||||
})
|
|
||||||
.run_and_coalesce()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check the binary sizes of examples
|
|
||||||
pub fn build_and_check_size<'c>(
|
|
||||||
globals: &Globals,
|
|
||||||
cargoarg: &'c Option<&'c str>,
|
|
||||||
backend: Backends,
|
|
||||||
examples: &'c [String],
|
|
||||||
arguments: &'c Option<ExtraArguments>,
|
|
||||||
) -> Vec<FinalRunResult<'c>> {
|
|
||||||
let target = backend.to_target();
|
|
||||||
let features = Some(target.and_features(backend.to_rtic_feature()));
|
|
||||||
|
|
||||||
let runner = examples_iter(examples).map(|example| {
|
|
||||||
// Make sure the requested example(s) are built
|
|
||||||
let cmd = CargoCommand::ExampleBuild {
|
|
||||||
cargoarg: &Some("--quiet"),
|
|
||||||
example,
|
|
||||||
target,
|
|
||||||
features: features.clone(),
|
|
||||||
mode: BuildMode::Release,
|
|
||||||
};
|
|
||||||
if let Err(err) = command_parser(globals, &cmd, false) {
|
|
||||||
error!("{err}");
|
|
||||||
}
|
|
||||||
|
|
||||||
let cmd = CargoCommand::ExampleSize {
|
|
||||||
cargoarg,
|
|
||||||
example,
|
|
||||||
target: backend.to_target(),
|
|
||||||
features: features.clone(),
|
|
||||||
mode: BuildMode::Release,
|
|
||||||
arguments: arguments.clone(),
|
|
||||||
};
|
|
||||||
(globals, cmd, false)
|
|
||||||
});
|
|
||||||
|
|
||||||
runner.run_and_coalesce()
|
|
||||||
}
|
|
|
@ -1,779 +0,0 @@
|
||||||
use log::{error, info, Level};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
argument_parsing::Globals, cargo_commands::FinalRunResult, ExtraArguments, Package, RunResult,
|
|
||||||
Target, TestRunError,
|
|
||||||
};
|
|
||||||
use core::fmt;
|
|
||||||
use std::{
|
|
||||||
fs::File,
|
|
||||||
io::Read,
|
|
||||||
process::{Command, Stdio},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
||||||
pub enum BuildMode {
|
|
||||||
Release,
|
|
||||||
Debug,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
||||||
pub enum OutputMode {
|
|
||||||
PipedAndCollected,
|
|
||||||
Inherited,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<OutputMode> for Stdio {
|
|
||||||
fn from(value: OutputMode) -> Self {
|
|
||||||
match value {
|
|
||||||
OutputMode::PipedAndCollected => Stdio::piped(),
|
|
||||||
OutputMode::Inherited => Stdio::inherit(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum CargoCommand<'a> {
|
|
||||||
// For future embedded-ci
|
|
||||||
#[allow(dead_code)]
|
|
||||||
Run {
|
|
||||||
cargoarg: &'a Option<&'a str>,
|
|
||||||
example: &'a str,
|
|
||||||
target: Target<'a>,
|
|
||||||
features: Option<String>,
|
|
||||||
mode: BuildMode,
|
|
||||||
},
|
|
||||||
Qemu {
|
|
||||||
cargoarg: &'a Option<&'a str>,
|
|
||||||
example: &'a str,
|
|
||||||
target: Target<'a>,
|
|
||||||
features: Option<String>,
|
|
||||||
mode: BuildMode,
|
|
||||||
},
|
|
||||||
ExampleBuild {
|
|
||||||
cargoarg: &'a Option<&'a str>,
|
|
||||||
example: &'a str,
|
|
||||||
target: Target<'a>,
|
|
||||||
features: Option<String>,
|
|
||||||
mode: BuildMode,
|
|
||||||
},
|
|
||||||
ExampleCheck {
|
|
||||||
cargoarg: &'a Option<&'a str>,
|
|
||||||
example: &'a str,
|
|
||||||
target: Target<'a>,
|
|
||||||
features: Option<String>,
|
|
||||||
mode: BuildMode,
|
|
||||||
},
|
|
||||||
Build {
|
|
||||||
cargoarg: &'a Option<&'a str>,
|
|
||||||
package: Option<Package>,
|
|
||||||
target: Target<'a>,
|
|
||||||
features: Option<String>,
|
|
||||||
mode: BuildMode,
|
|
||||||
},
|
|
||||||
Check {
|
|
||||||
cargoarg: &'a Option<&'a str>,
|
|
||||||
package: Option<Package>,
|
|
||||||
target: Target<'a>,
|
|
||||||
features: Option<String>,
|
|
||||||
mode: BuildMode,
|
|
||||||
},
|
|
||||||
Clippy {
|
|
||||||
cargoarg: &'a Option<&'a str>,
|
|
||||||
package: Option<Package>,
|
|
||||||
target: Target<'a>,
|
|
||||||
features: Option<String>,
|
|
||||||
},
|
|
||||||
Format {
|
|
||||||
cargoarg: &'a Option<&'a str>,
|
|
||||||
package: Option<Package>,
|
|
||||||
check_only: bool,
|
|
||||||
},
|
|
||||||
Doc {
|
|
||||||
cargoarg: &'a Option<&'a str>,
|
|
||||||
features: Option<String>,
|
|
||||||
arguments: Option<ExtraArguments>,
|
|
||||||
},
|
|
||||||
Test {
|
|
||||||
package: Option<Package>,
|
|
||||||
features: Option<String>,
|
|
||||||
test: Option<String>,
|
|
||||||
},
|
|
||||||
Book {
|
|
||||||
arguments: Option<ExtraArguments>,
|
|
||||||
},
|
|
||||||
ExampleSize {
|
|
||||||
cargoarg: &'a Option<&'a str>,
|
|
||||||
example: &'a str,
|
|
||||||
target: Target<'a>,
|
|
||||||
features: Option<String>,
|
|
||||||
mode: BuildMode,
|
|
||||||
arguments: Option<ExtraArguments>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::fmt::Display for CargoCommand<'_> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
let p = |p: &Option<Package>| {
|
|
||||||
if let Some(package) = p {
|
|
||||||
format!("package {package}")
|
|
||||||
} else {
|
|
||||||
format!("default package")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let feat = |f: &Option<String>| {
|
|
||||||
if let Some(features) = f {
|
|
||||||
format!("\"{features}\"")
|
|
||||||
} else {
|
|
||||||
format!("no features")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let carg = |f: &&Option<&str>| {
|
|
||||||
if let Some(cargoarg) = f {
|
|
||||||
format!("{cargoarg}")
|
|
||||||
} else {
|
|
||||||
format!("no cargo args")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let details = |target: &Target,
|
|
||||||
mode: &BuildMode,
|
|
||||||
features: &Option<String>,
|
|
||||||
cargoarg: &&Option<&str>| {
|
|
||||||
let feat = feat(features);
|
|
||||||
let carg = carg(cargoarg);
|
|
||||||
if cargoarg.is_some() {
|
|
||||||
format!("({target}, {mode}, {feat}, {carg})")
|
|
||||||
} else {
|
|
||||||
format!("({target}, {mode}, {feat})")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match self {
|
|
||||||
CargoCommand::Run {
|
|
||||||
cargoarg,
|
|
||||||
example,
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
mode,
|
|
||||||
} => write!(
|
|
||||||
f,
|
|
||||||
"Run example {example} {}",
|
|
||||||
details(target, mode, features, cargoarg)
|
|
||||||
),
|
|
||||||
CargoCommand::Qemu {
|
|
||||||
cargoarg,
|
|
||||||
example,
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
mode,
|
|
||||||
} => write!(
|
|
||||||
f,
|
|
||||||
"Run example {example} in QEMU {}",
|
|
||||||
details(target, mode, features, cargoarg)
|
|
||||||
),
|
|
||||||
CargoCommand::ExampleBuild {
|
|
||||||
cargoarg,
|
|
||||||
example,
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
mode,
|
|
||||||
} => write!(
|
|
||||||
f,
|
|
||||||
"Build example {example} {}",
|
|
||||||
details(target, mode, features, cargoarg)
|
|
||||||
),
|
|
||||||
CargoCommand::ExampleCheck {
|
|
||||||
cargoarg,
|
|
||||||
example,
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
mode,
|
|
||||||
} => write!(
|
|
||||||
f,
|
|
||||||
"Check example {example} {}",
|
|
||||||
details(target, mode, features, cargoarg)
|
|
||||||
),
|
|
||||||
CargoCommand::Build {
|
|
||||||
cargoarg,
|
|
||||||
package,
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
mode,
|
|
||||||
} => {
|
|
||||||
let package = p(package);
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"Build {package} {}",
|
|
||||||
details(target, mode, features, cargoarg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
CargoCommand::Check {
|
|
||||||
cargoarg,
|
|
||||||
package,
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
mode,
|
|
||||||
} => {
|
|
||||||
let package = p(package);
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"Check {package} {}",
|
|
||||||
details(target, mode, features, cargoarg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
CargoCommand::Clippy {
|
|
||||||
cargoarg,
|
|
||||||
package,
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
} => {
|
|
||||||
let package = p(package);
|
|
||||||
let features = feat(features);
|
|
||||||
let carg = carg(cargoarg);
|
|
||||||
if cargoarg.is_some() {
|
|
||||||
write!(f, "Clippy {package} ({target}, {features}, {carg})")
|
|
||||||
} else {
|
|
||||||
write!(f, "Clippy {package} ({target}, {features})")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CargoCommand::Format {
|
|
||||||
cargoarg,
|
|
||||||
package,
|
|
||||||
check_only,
|
|
||||||
} => {
|
|
||||||
let package = p(package);
|
|
||||||
let carg = carg(cargoarg);
|
|
||||||
|
|
||||||
let carg = if cargoarg.is_some() {
|
|
||||||
format!("(cargo args: {carg})")
|
|
||||||
} else {
|
|
||||||
format!("")
|
|
||||||
};
|
|
||||||
|
|
||||||
if *check_only {
|
|
||||||
write!(f, "Check format for {package} {carg}")
|
|
||||||
} else {
|
|
||||||
write!(f, "Format {package} {carg}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CargoCommand::Doc {
|
|
||||||
cargoarg,
|
|
||||||
features,
|
|
||||||
arguments,
|
|
||||||
} => {
|
|
||||||
let feat = feat(features);
|
|
||||||
let carg = carg(cargoarg);
|
|
||||||
let arguments = arguments
|
|
||||||
.clone()
|
|
||||||
.map(|a| format!("{a}"))
|
|
||||||
.unwrap_or_else(|| "no extra arguments".into());
|
|
||||||
if cargoarg.is_some() {
|
|
||||||
write!(f, "Document ({feat}, {carg}, {arguments})")
|
|
||||||
} else {
|
|
||||||
write!(f, "Document ({feat}, {arguments})")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CargoCommand::Test {
|
|
||||||
package,
|
|
||||||
features,
|
|
||||||
test,
|
|
||||||
} => {
|
|
||||||
let p = p(package);
|
|
||||||
let test = test
|
|
||||||
.clone()
|
|
||||||
.map(|t| format!("test {t}"))
|
|
||||||
.unwrap_or("all tests".into());
|
|
||||||
let feat = feat(features);
|
|
||||||
write!(f, "Run {test} in {p} (features: {feat})")
|
|
||||||
}
|
|
||||||
CargoCommand::Book { arguments: _ } => write!(f, "Build the book"),
|
|
||||||
CargoCommand::ExampleSize {
|
|
||||||
cargoarg,
|
|
||||||
example,
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
mode,
|
|
||||||
arguments: _,
|
|
||||||
} => {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"Compute size of example {example} {}",
|
|
||||||
details(target, mode, features, cargoarg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CargoCommand<'a> {
|
|
||||||
pub fn as_cmd_string(&self) -> String {
|
|
||||||
let executable = self.executable();
|
|
||||||
let args = self.args().join(" ");
|
|
||||||
format!("{executable} {args}")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn command(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
CargoCommand::Run { .. } | CargoCommand::Qemu { .. } => "run",
|
|
||||||
CargoCommand::ExampleCheck { .. } | CargoCommand::Check { .. } => "check",
|
|
||||||
CargoCommand::ExampleBuild { .. } | CargoCommand::Build { .. } => "build",
|
|
||||||
CargoCommand::ExampleSize { .. } => "size",
|
|
||||||
CargoCommand::Clippy { .. } => "clippy",
|
|
||||||
CargoCommand::Format { .. } => "fmt",
|
|
||||||
CargoCommand::Doc { .. } => "doc",
|
|
||||||
CargoCommand::Book { .. } => "build",
|
|
||||||
CargoCommand::Test { .. } => "test",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn executable(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
CargoCommand::Run { .. }
|
|
||||||
| CargoCommand::Qemu { .. }
|
|
||||||
| CargoCommand::ExampleCheck { .. }
|
|
||||||
| CargoCommand::Check { .. }
|
|
||||||
| CargoCommand::ExampleBuild { .. }
|
|
||||||
| CargoCommand::Build { .. }
|
|
||||||
| CargoCommand::ExampleSize { .. }
|
|
||||||
| CargoCommand::Clippy { .. }
|
|
||||||
| CargoCommand::Format { .. }
|
|
||||||
| CargoCommand::Test { .. }
|
|
||||||
| CargoCommand::Doc { .. } => "cargo",
|
|
||||||
CargoCommand::Book { .. } => "mdbook",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn args(&self) -> Vec<&str> {
|
|
||||||
match self {
|
|
||||||
// For future embedded-ci, for now the same as Qemu
|
|
||||||
CargoCommand::Run {
|
|
||||||
cargoarg,
|
|
||||||
example,
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
mode,
|
|
||||||
} => {
|
|
||||||
let mut args = vec!["+nightly"];
|
|
||||||
if let Some(cargoarg) = cargoarg {
|
|
||||||
args.extend_from_slice(&[cargoarg]);
|
|
||||||
}
|
|
||||||
args.extend_from_slice(&[
|
|
||||||
self.command(),
|
|
||||||
"--example",
|
|
||||||
example,
|
|
||||||
"--target",
|
|
||||||
target.triple(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if let Some(feature) = features {
|
|
||||||
args.extend_from_slice(&["--features", feature]);
|
|
||||||
}
|
|
||||||
if let Some(flag) = mode.to_flag() {
|
|
||||||
args.push(flag);
|
|
||||||
}
|
|
||||||
args
|
|
||||||
}
|
|
||||||
CargoCommand::Qemu {
|
|
||||||
cargoarg,
|
|
||||||
example,
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
mode,
|
|
||||||
} => {
|
|
||||||
let mut args = vec!["+nightly"];
|
|
||||||
if let Some(cargoarg) = cargoarg {
|
|
||||||
args.extend_from_slice(&[cargoarg]);
|
|
||||||
}
|
|
||||||
args.extend_from_slice(&[
|
|
||||||
self.command(),
|
|
||||||
"--example",
|
|
||||||
example,
|
|
||||||
"--target",
|
|
||||||
target.triple(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if let Some(feature) = features {
|
|
||||||
args.extend_from_slice(&["--features", feature]);
|
|
||||||
}
|
|
||||||
if let Some(flag) = mode.to_flag() {
|
|
||||||
args.push(flag);
|
|
||||||
}
|
|
||||||
args
|
|
||||||
}
|
|
||||||
CargoCommand::Build {
|
|
||||||
cargoarg,
|
|
||||||
package,
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
mode,
|
|
||||||
} => {
|
|
||||||
let mut args = vec!["+nightly"];
|
|
||||||
if let Some(cargoarg) = cargoarg {
|
|
||||||
args.extend_from_slice(&[cargoarg]);
|
|
||||||
}
|
|
||||||
|
|
||||||
args.extend_from_slice(&[self.command(), "--target", target.triple()]);
|
|
||||||
|
|
||||||
if let Some(package) = package {
|
|
||||||
args.extend_from_slice(&["--package", package.name()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(feature) = features {
|
|
||||||
args.extend_from_slice(&["--features", feature]);
|
|
||||||
}
|
|
||||||
if let Some(flag) = mode.to_flag() {
|
|
||||||
args.push(flag);
|
|
||||||
}
|
|
||||||
args
|
|
||||||
}
|
|
||||||
CargoCommand::Check {
|
|
||||||
cargoarg,
|
|
||||||
package,
|
|
||||||
target: _,
|
|
||||||
features,
|
|
||||||
mode,
|
|
||||||
} => {
|
|
||||||
let mut args = vec!["+nightly"];
|
|
||||||
if let Some(cargoarg) = cargoarg {
|
|
||||||
args.extend_from_slice(&[cargoarg]);
|
|
||||||
}
|
|
||||||
args.extend_from_slice(&[self.command()]);
|
|
||||||
|
|
||||||
if let Some(package) = package {
|
|
||||||
args.extend_from_slice(&["--package", package.name()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(feature) = features {
|
|
||||||
args.extend_from_slice(&["--features", feature]);
|
|
||||||
}
|
|
||||||
if let Some(flag) = mode.to_flag() {
|
|
||||||
args.push(flag);
|
|
||||||
}
|
|
||||||
args
|
|
||||||
}
|
|
||||||
CargoCommand::Clippy {
|
|
||||||
cargoarg,
|
|
||||||
package,
|
|
||||||
target: _,
|
|
||||||
features,
|
|
||||||
} => {
|
|
||||||
let mut args = vec!["+nightly"];
|
|
||||||
if let Some(cargoarg) = cargoarg {
|
|
||||||
args.extend_from_slice(&[cargoarg]);
|
|
||||||
}
|
|
||||||
|
|
||||||
args.extend_from_slice(&[self.command()]);
|
|
||||||
|
|
||||||
if let Some(package) = package {
|
|
||||||
args.extend_from_slice(&["--package", package.name()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(feature) = features {
|
|
||||||
args.extend_from_slice(&["--features", feature]);
|
|
||||||
}
|
|
||||||
args
|
|
||||||
}
|
|
||||||
CargoCommand::Doc {
|
|
||||||
cargoarg,
|
|
||||||
features,
|
|
||||||
arguments,
|
|
||||||
} => {
|
|
||||||
let mut args = vec!["+nightly"];
|
|
||||||
if let Some(cargoarg) = cargoarg {
|
|
||||||
args.extend_from_slice(&[cargoarg]);
|
|
||||||
}
|
|
||||||
|
|
||||||
args.extend_from_slice(&[self.command()]);
|
|
||||||
|
|
||||||
if let Some(feature) = features {
|
|
||||||
args.extend_from_slice(&["--features", feature]);
|
|
||||||
}
|
|
||||||
if let Some(ExtraArguments::Other(arguments)) = arguments {
|
|
||||||
for arg in arguments {
|
|
||||||
args.extend_from_slice(&[arg.as_str()]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
args
|
|
||||||
}
|
|
||||||
CargoCommand::Test {
|
|
||||||
package,
|
|
||||||
features,
|
|
||||||
test,
|
|
||||||
} => {
|
|
||||||
let mut args = vec!["+nightly"];
|
|
||||||
args.extend_from_slice(&[self.command()]);
|
|
||||||
|
|
||||||
if let Some(package) = package {
|
|
||||||
args.extend_from_slice(&["--package", package.name()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(feature) = features {
|
|
||||||
args.extend_from_slice(&["--features", feature]);
|
|
||||||
}
|
|
||||||
if let Some(test) = test {
|
|
||||||
args.extend_from_slice(&["--test", test]);
|
|
||||||
}
|
|
||||||
args
|
|
||||||
}
|
|
||||||
CargoCommand::Book { arguments } => {
|
|
||||||
let mut args = vec![];
|
|
||||||
|
|
||||||
if let Some(ExtraArguments::Other(arguments)) = arguments {
|
|
||||||
for arg in arguments {
|
|
||||||
args.extend_from_slice(&[arg.as_str()]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If no argument given, run mdbook build
|
|
||||||
// with default path to book
|
|
||||||
args.extend_from_slice(&[self.command()]);
|
|
||||||
args.extend_from_slice(&["book/en"]);
|
|
||||||
}
|
|
||||||
args
|
|
||||||
}
|
|
||||||
CargoCommand::Format {
|
|
||||||
cargoarg,
|
|
||||||
package,
|
|
||||||
check_only,
|
|
||||||
} => {
|
|
||||||
let mut args = vec!["+nightly", self.command()];
|
|
||||||
if let Some(cargoarg) = cargoarg {
|
|
||||||
args.extend_from_slice(&[cargoarg]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(package) = package {
|
|
||||||
args.extend_from_slice(&["--package", package.name()]);
|
|
||||||
}
|
|
||||||
if *check_only {
|
|
||||||
args.extend_from_slice(&["--check"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
args
|
|
||||||
}
|
|
||||||
CargoCommand::ExampleBuild {
|
|
||||||
cargoarg,
|
|
||||||
example,
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
mode,
|
|
||||||
} => {
|
|
||||||
let mut args = vec!["+nightly"];
|
|
||||||
if let Some(cargoarg) = cargoarg {
|
|
||||||
args.extend_from_slice(&[cargoarg]);
|
|
||||||
}
|
|
||||||
args.extend_from_slice(&[
|
|
||||||
self.command(),
|
|
||||||
"--example",
|
|
||||||
example,
|
|
||||||
"--target",
|
|
||||||
target.triple(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if let Some(feature) = features {
|
|
||||||
args.extend_from_slice(&["--features", feature]);
|
|
||||||
}
|
|
||||||
if let Some(flag) = mode.to_flag() {
|
|
||||||
args.push(flag);
|
|
||||||
}
|
|
||||||
args
|
|
||||||
}
|
|
||||||
CargoCommand::ExampleCheck {
|
|
||||||
cargoarg,
|
|
||||||
example,
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
mode,
|
|
||||||
} => {
|
|
||||||
let mut args = vec!["+nightly"];
|
|
||||||
if let Some(cargoarg) = cargoarg {
|
|
||||||
args.extend_from_slice(&[cargoarg]);
|
|
||||||
}
|
|
||||||
args.extend_from_slice(&[
|
|
||||||
self.command(),
|
|
||||||
"--example",
|
|
||||||
example,
|
|
||||||
"--target",
|
|
||||||
target.triple(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if let Some(feature) = features {
|
|
||||||
args.extend_from_slice(&["--features", feature]);
|
|
||||||
}
|
|
||||||
if let Some(flag) = mode.to_flag() {
|
|
||||||
args.push(flag);
|
|
||||||
}
|
|
||||||
args
|
|
||||||
}
|
|
||||||
CargoCommand::ExampleSize {
|
|
||||||
cargoarg,
|
|
||||||
example,
|
|
||||||
target,
|
|
||||||
features,
|
|
||||||
mode,
|
|
||||||
arguments,
|
|
||||||
} => {
|
|
||||||
let mut args = vec!["+nightly"];
|
|
||||||
if let Some(cargoarg) = cargoarg {
|
|
||||||
args.extend_from_slice(&[cargoarg]);
|
|
||||||
}
|
|
||||||
args.extend_from_slice(&[
|
|
||||||
self.command(),
|
|
||||||
"--example",
|
|
||||||
example,
|
|
||||||
"--target",
|
|
||||||
target.triple(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if let Some(feature_name) = features {
|
|
||||||
args.extend_from_slice(&["--features", feature_name]);
|
|
||||||
}
|
|
||||||
if let Some(flag) = mode.to_flag() {
|
|
||||||
args.push(flag);
|
|
||||||
}
|
|
||||||
if let Some(ExtraArguments::Other(arguments)) = arguments {
|
|
||||||
// Arguments to cargo size must be passed after "--"
|
|
||||||
args.extend_from_slice(&["--"]);
|
|
||||||
for arg in arguments {
|
|
||||||
args.extend_from_slice(&[arg.as_str()]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
args
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BuildMode {
|
|
||||||
#[allow(clippy::wrong_self_convention)]
|
|
||||||
pub fn to_flag(&self) -> Option<&str> {
|
|
||||||
match self {
|
|
||||||
BuildMode::Release => Some("--release"),
|
|
||||||
BuildMode::Debug => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for BuildMode {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
let cmd = match self {
|
|
||||||
BuildMode::Release => "release",
|
|
||||||
BuildMode::Debug => "debug",
|
|
||||||
};
|
|
||||||
|
|
||||||
write!(f, "{cmd}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_command(command: &CargoCommand, stderr_mode: OutputMode) -> anyhow::Result<RunResult> {
|
|
||||||
log::info!("👟 {command}");
|
|
||||||
|
|
||||||
let result = Command::new(command.executable())
|
|
||||||
.args(command.args())
|
|
||||||
.stdout(Stdio::piped())
|
|
||||||
.stderr(stderr_mode)
|
|
||||||
.output()?;
|
|
||||||
|
|
||||||
let exit_status = result.status;
|
|
||||||
let stderr = String::from_utf8(result.stderr).unwrap_or("Not displayable".into());
|
|
||||||
let stdout = String::from_utf8(result.stdout).unwrap_or("Not displayable".into());
|
|
||||||
|
|
||||||
Ok(RunResult {
|
|
||||||
exit_status,
|
|
||||||
stdout,
|
|
||||||
stderr,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if `run` was successful.
|
|
||||||
/// returns Ok in case the run went as expected,
|
|
||||||
/// Err otherwise
|
|
||||||
pub fn run_successful(run: &RunResult, expected_output_file: &str) -> Result<(), TestRunError> {
|
|
||||||
let mut file_handle =
|
|
||||||
File::open(expected_output_file).map_err(|_| TestRunError::FileError {
|
|
||||||
file: expected_output_file.to_owned(),
|
|
||||||
})?;
|
|
||||||
let mut expected_output = String::new();
|
|
||||||
file_handle
|
|
||||||
.read_to_string(&mut expected_output)
|
|
||||||
.map_err(|_| TestRunError::FileError {
|
|
||||||
file: expected_output_file.to_owned(),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if expected_output != run.stdout {
|
|
||||||
Err(TestRunError::FileCmpError {
|
|
||||||
expected: expected_output.clone(),
|
|
||||||
got: run.stdout.clone(),
|
|
||||||
})
|
|
||||||
} else if !run.exit_status.success() {
|
|
||||||
Err(TestRunError::CommandError(run.clone()))
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle_results(globals: &Globals, results: Vec<FinalRunResult>) -> anyhow::Result<()> {
|
|
||||||
let errors = results.iter().filter_map(|r| {
|
|
||||||
if let FinalRunResult::Failed(c, r) = r {
|
|
||||||
Some((c, r))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let successes = results.iter().filter_map(|r| {
|
|
||||||
if let FinalRunResult::Success(c, r) = r {
|
|
||||||
Some((c, r))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let log_stdout_stderr = |level: Level| {
|
|
||||||
move |(command, result): (&CargoCommand, &RunResult)| {
|
|
||||||
let stdout = &result.stdout;
|
|
||||||
let stderr = &result.stderr;
|
|
||||||
if !stdout.is_empty() && !stderr.is_empty() {
|
|
||||||
log::log!(
|
|
||||||
level,
|
|
||||||
"Output for \"{command}\"\nStdout:\n{stdout}\nStderr:\n{stderr}"
|
|
||||||
);
|
|
||||||
} else if !stdout.is_empty() {
|
|
||||||
log::log!(
|
|
||||||
level,
|
|
||||||
"Output for \"{command}\":\nStdout:\n{}",
|
|
||||||
stdout.trim_end()
|
|
||||||
);
|
|
||||||
} else if !stderr.is_empty() {
|
|
||||||
log::log!(
|
|
||||||
level,
|
|
||||||
"Output for \"{command}\"\nStderr:\n{}",
|
|
||||||
stderr.trim_end()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
successes.clone().for_each(log_stdout_stderr(Level::Debug));
|
|
||||||
errors.clone().for_each(log_stdout_stderr(Level::Error));
|
|
||||||
|
|
||||||
successes.for_each(|(cmd, _)| {
|
|
||||||
if globals.verbose > 0 {
|
|
||||||
info!("✅ Success: {cmd}\n {}", cmd.as_cmd_string());
|
|
||||||
} else {
|
|
||||||
info!("✅ Success: {cmd}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
errors.clone().for_each(|(cmd, _)| {
|
|
||||||
error!("❌ Failed: {cmd}\n {}", cmd.as_cmd_string());
|
|
||||||
});
|
|
||||||
|
|
||||||
let ecount = errors.count();
|
|
||||||
if ecount != 0 {
|
|
||||||
Err(anyhow::anyhow!("{ecount} commands failed."))
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +1,19 @@
|
||||||
mod argument_parsing;
|
mod argument_parsing;
|
||||||
mod build;
|
mod build;
|
||||||
mod cargo_commands;
|
mod cargo_command;
|
||||||
mod command;
|
mod run;
|
||||||
|
|
||||||
use argument_parsing::{ExtraArguments, Globals, Package};
|
use argument_parsing::ExtraArguments;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use command::OutputMode;
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use diffy::{create_patch, PatchFormatter};
|
use std::{path::Path, str};
|
||||||
use std::{
|
|
||||||
error::Error,
|
|
||||||
ffi::OsString,
|
|
||||||
fs::File,
|
|
||||||
io::prelude::*,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
process::ExitStatus,
|
|
||||||
str,
|
|
||||||
};
|
|
||||||
|
|
||||||
use log::{error, info, log_enabled, trace, Level};
|
use log::{error, info, log_enabled, trace, Level};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
argument_parsing::{Backends, BuildOrCheck, Cli, Commands},
|
argument_parsing::{Backends, BuildOrCheck, Cli, Commands},
|
||||||
build::init_build_dir,
|
build::init_build_dir,
|
||||||
cargo_commands::{
|
run::*,
|
||||||
build_and_check_size, cargo, cargo_book, cargo_clippy, cargo_doc, cargo_example,
|
|
||||||
cargo_format, cargo_test, run_test,
|
|
||||||
},
|
|
||||||
command::{handle_results, run_command, run_successful, CargoCommand},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
@ -69,56 +55,6 @@ const ARMV7M: Target = Target::new("thumbv7m-none-eabi", false);
|
||||||
const ARMV8MBASE: Target = Target::new("thumbv8m.base-none-eabi", false);
|
const ARMV8MBASE: Target = Target::new("thumbv8m.base-none-eabi", false);
|
||||||
const ARMV8MMAIN: Target = Target::new("thumbv8m.main-none-eabi", false);
|
const ARMV8MMAIN: Target = Target::new("thumbv8m.main-none-eabi", false);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct RunResult {
|
|
||||||
exit_status: ExitStatus,
|
|
||||||
stdout: String,
|
|
||||||
stderr: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum TestRunError {
|
|
||||||
FileCmpError { expected: String, got: String },
|
|
||||||
FileError { file: String },
|
|
||||||
PathConversionError(OsString),
|
|
||||||
CommandError(RunResult),
|
|
||||||
IncompatibleCommand,
|
|
||||||
}
|
|
||||||
impl fmt::Display for TestRunError {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
TestRunError::FileCmpError { expected, got } => {
|
|
||||||
let patch = create_patch(expected, got);
|
|
||||||
writeln!(f, "Differing output in files.\n")?;
|
|
||||||
let pf = PatchFormatter::new().with_color();
|
|
||||||
writeln!(f, "{}", pf.fmt_patch(&patch))?;
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"See flag --overwrite-expected to create/update expected output."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
TestRunError::FileError { file } => {
|
|
||||||
write!(f, "File error on: {file}\nSee flag --overwrite-expected to create/update expected output.")
|
|
||||||
}
|
|
||||||
TestRunError::CommandError(e) => {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"Command failed with exit status {}: {}",
|
|
||||||
e.exit_status, e.stdout
|
|
||||||
)
|
|
||||||
}
|
|
||||||
TestRunError::PathConversionError(p) => {
|
|
||||||
write!(f, "Can't convert path from `OsString` to `String`: {p:?}")
|
|
||||||
}
|
|
||||||
TestRunError::IncompatibleCommand => {
|
|
||||||
write!(f, "Can't run that command in this context")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for TestRunError {}
|
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
// if there's an `xtask` folder, we're *probably* at the root of this repo (we can't just
|
// if there's an `xtask` folder, we're *probably* at the root of this repo (we can't just
|
||||||
// check the name of `env::current_dir()` because people might clone it into a different name)
|
// check the name of `env::current_dir()` because people might clone it into a different name)
|
||||||
|
@ -152,6 +88,12 @@ fn main() -> anyhow::Result<()> {
|
||||||
|
|
||||||
trace!("default logging level: {0}", globals.verbose);
|
trace!("default logging level: {0}", globals.verbose);
|
||||||
|
|
||||||
|
log::debug!(
|
||||||
|
"Stderr of child processes is inherited: {}",
|
||||||
|
globals.stderr_inherited
|
||||||
|
);
|
||||||
|
log::debug!("Partial features: {}", globals.partial);
|
||||||
|
|
||||||
let backend = if let Some(backend) = globals.backend {
|
let backend = if let Some(backend) = globals.backend {
|
||||||
backend
|
backend
|
||||||
} else {
|
} else {
|
||||||
|
@ -265,7 +207,7 @@ fn main() -> anyhow::Result<()> {
|
||||||
Commands::Qemu(args) | Commands::Run(args) => {
|
Commands::Qemu(args) | Commands::Run(args) => {
|
||||||
// x86_64 target not valid
|
// x86_64 target not valid
|
||||||
info!("Testing for backend: {backend:?}");
|
info!("Testing for backend: {backend:?}");
|
||||||
run_test(
|
qemu_run_examples(
|
||||||
globals,
|
globals,
|
||||||
&cargologlevel,
|
&cargologlevel,
|
||||||
backend,
|
backend,
|
||||||
|
@ -285,71 +227,15 @@ fn main() -> anyhow::Result<()> {
|
||||||
info!("Running mdbook");
|
info!("Running mdbook");
|
||||||
cargo_book(globals, &args.arguments)
|
cargo_book(globals, &args.arguments)
|
||||||
}
|
}
|
||||||
|
Commands::UsageExampleCheck(examples) => {
|
||||||
|
info!("Checking usage examples");
|
||||||
|
cargo_usage_example(globals, BuildOrCheck::Check, examples.examples()?)
|
||||||
|
}
|
||||||
|
Commands::UsageExampleBuild(examples) => {
|
||||||
|
info!("Building usage examples");
|
||||||
|
cargo_usage_example(globals, BuildOrCheck::Build, examples.examples()?)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handle_results(globals, final_run_results)
|
handle_results(globals, final_run_results).map_err(|_| anyhow::anyhow!("Commands failed"))
|
||||||
}
|
|
||||||
|
|
||||||
// run example binary `example`
|
|
||||||
fn command_parser(
|
|
||||||
glob: &Globals,
|
|
||||||
command: &CargoCommand,
|
|
||||||
overwrite: bool,
|
|
||||||
) -> anyhow::Result<RunResult> {
|
|
||||||
let output_mode = if glob.stderr_inherited {
|
|
||||||
OutputMode::Inherited
|
|
||||||
} else {
|
|
||||||
OutputMode::PipedAndCollected
|
|
||||||
};
|
|
||||||
|
|
||||||
match *command {
|
|
||||||
CargoCommand::Qemu { example, .. } | CargoCommand::Run { example, .. } => {
|
|
||||||
let run_file = format!("{example}.run");
|
|
||||||
let expected_output_file = ["rtic", "ci", "expected", &run_file]
|
|
||||||
.iter()
|
|
||||||
.collect::<PathBuf>()
|
|
||||||
.into_os_string()
|
|
||||||
.into_string()
|
|
||||||
.map_err(TestRunError::PathConversionError)?;
|
|
||||||
|
|
||||||
// cargo run <..>
|
|
||||||
info!("Running example: {example}");
|
|
||||||
let cargo_run_result = run_command(command, output_mode)?;
|
|
||||||
info!("{}", cargo_run_result.stdout);
|
|
||||||
|
|
||||||
// Create a file for the expected output if it does not exist or mismatches
|
|
||||||
if overwrite {
|
|
||||||
let result = run_successful(&cargo_run_result, &expected_output_file);
|
|
||||||
if let Err(e) = result {
|
|
||||||
// FileError means the file did not exist or was unreadable
|
|
||||||
error!("Error: {e}");
|
|
||||||
let mut file_handle = File::create(&expected_output_file).map_err(|_| {
|
|
||||||
TestRunError::FileError {
|
|
||||||
file: expected_output_file.clone(),
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
info!("Flag --overwrite-expected enabled");
|
|
||||||
info!("Creating/updating file: {expected_output_file}");
|
|
||||||
file_handle.write_all(cargo_run_result.stdout.as_bytes())?;
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
run_successful(&cargo_run_result, &expected_output_file)?;
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(cargo_run_result)
|
|
||||||
}
|
|
||||||
CargoCommand::Format { .. }
|
|
||||||
| CargoCommand::ExampleCheck { .. }
|
|
||||||
| CargoCommand::ExampleBuild { .. }
|
|
||||||
| CargoCommand::Check { .. }
|
|
||||||
| CargoCommand::Build { .. }
|
|
||||||
| CargoCommand::Clippy { .. }
|
|
||||||
| CargoCommand::Doc { .. }
|
|
||||||
| CargoCommand::Test { .. }
|
|
||||||
| CargoCommand::Book { .. }
|
|
||||||
| CargoCommand::ExampleSize { .. } => {
|
|
||||||
let cargo_result = run_command(command, output_mode)?;
|
|
||||||
Ok(cargo_result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
501
xtask/src/run.rs
Normal file
501
xtask/src/run.rs
Normal file
|
@ -0,0 +1,501 @@
|
||||||
|
use std::{
|
||||||
|
fs::File,
|
||||||
|
io::Write,
|
||||||
|
path::PathBuf,
|
||||||
|
process::{Command, Stdio},
|
||||||
|
};
|
||||||
|
|
||||||
|
mod results;
|
||||||
|
pub use results::handle_results;
|
||||||
|
|
||||||
|
mod data;
|
||||||
|
use data::*;
|
||||||
|
|
||||||
|
mod iter;
|
||||||
|
use iter::{into_iter, CoalescingRunner};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
argument_parsing::{Backends, BuildOrCheck, ExtraArguments, Globals, PackageOpt, TestMetadata},
|
||||||
|
cargo_command::{BuildMode, CargoCommand},
|
||||||
|
};
|
||||||
|
|
||||||
|
use log::{error, info};
|
||||||
|
|
||||||
|
#[cfg(feature = "rayon")]
|
||||||
|
use rayon::prelude::*;
|
||||||
|
|
||||||
|
fn run_and_convert<'a>(
|
||||||
|
(global, command, overwrite): (&Globals, CargoCommand<'a>, bool),
|
||||||
|
) -> FinalRunResult<'a> {
|
||||||
|
// Run the command
|
||||||
|
let result = command_parser(global, &command, overwrite);
|
||||||
|
|
||||||
|
let output = match result {
|
||||||
|
// If running the command succeeded without looking at any of the results,
|
||||||
|
// log the data and see if the actual execution was succesfull too.
|
||||||
|
Ok(result) => {
|
||||||
|
if result.exit_status.success() {
|
||||||
|
FinalRunResult::Success(command, result)
|
||||||
|
} else {
|
||||||
|
FinalRunResult::Failed(command, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If it didn't and some IO error occured, just panic
|
||||||
|
Err(e) => FinalRunResult::CommandError(command, e),
|
||||||
|
};
|
||||||
|
|
||||||
|
log::trace!("Final result: {output:?}");
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
// run example binary `example`
|
||||||
|
fn command_parser(
|
||||||
|
glob: &Globals,
|
||||||
|
command: &CargoCommand,
|
||||||
|
overwrite: bool,
|
||||||
|
) -> anyhow::Result<RunResult> {
|
||||||
|
let output_mode = if glob.stderr_inherited {
|
||||||
|
OutputMode::Inherited
|
||||||
|
} else {
|
||||||
|
OutputMode::PipedAndCollected
|
||||||
|
};
|
||||||
|
|
||||||
|
match *command {
|
||||||
|
CargoCommand::Qemu { example, .. } | CargoCommand::Run { example, .. } => {
|
||||||
|
/// Check if `run` was successful.
|
||||||
|
/// returns Ok in case the run went as expected,
|
||||||
|
/// Err otherwise
|
||||||
|
pub fn run_successful(
|
||||||
|
run: &RunResult,
|
||||||
|
expected_output_file: &str,
|
||||||
|
) -> Result<(), TestRunError> {
|
||||||
|
let file = expected_output_file.to_string();
|
||||||
|
|
||||||
|
let expected_output = std::fs::read(expected_output_file)
|
||||||
|
.map(|d| {
|
||||||
|
String::from_utf8(d)
|
||||||
|
.map_err(|_| TestRunError::FileError { file: file.clone() })
|
||||||
|
})
|
||||||
|
.map_err(|_| TestRunError::FileError { file })??;
|
||||||
|
|
||||||
|
let res = if expected_output != run.stdout {
|
||||||
|
Err(TestRunError::FileCmpError {
|
||||||
|
expected: expected_output.clone(),
|
||||||
|
got: run.stdout.clone(),
|
||||||
|
})
|
||||||
|
} else if !run.exit_status.success() {
|
||||||
|
Err(TestRunError::CommandError(run.clone()))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
if res.is_ok() {
|
||||||
|
log::info!("✅ Success.");
|
||||||
|
} else {
|
||||||
|
log::error!("❌ Command failed. Run to completion for the summary.");
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
let run_file = format!("{example}.run");
|
||||||
|
let expected_output_file = ["rtic", "ci", "expected", &run_file]
|
||||||
|
.iter()
|
||||||
|
.collect::<PathBuf>()
|
||||||
|
.into_os_string()
|
||||||
|
.into_string()
|
||||||
|
.map_err(TestRunError::PathConversionError)?;
|
||||||
|
|
||||||
|
// cargo run <..>
|
||||||
|
let cargo_run_result = run_command(command, output_mode, false)?;
|
||||||
|
|
||||||
|
// Create a file for the expected output if it does not exist or mismatches
|
||||||
|
if overwrite {
|
||||||
|
let result = run_successful(&cargo_run_result, &expected_output_file);
|
||||||
|
if let Err(e) = result {
|
||||||
|
// FileError means the file did not exist or was unreadable
|
||||||
|
error!("Error: {e}");
|
||||||
|
let mut file_handle = File::create(&expected_output_file).map_err(|_| {
|
||||||
|
TestRunError::FileError {
|
||||||
|
file: expected_output_file.clone(),
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
info!("Flag --overwrite-expected enabled");
|
||||||
|
info!("Creating/updating file: {expected_output_file}");
|
||||||
|
file_handle.write_all(cargo_run_result.stdout.as_bytes())?;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
run_successful(&cargo_run_result, &expected_output_file)?;
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(cargo_run_result)
|
||||||
|
}
|
||||||
|
CargoCommand::Format { .. }
|
||||||
|
| CargoCommand::ExampleCheck { .. }
|
||||||
|
| CargoCommand::ExampleBuild { .. }
|
||||||
|
| CargoCommand::Check { .. }
|
||||||
|
| CargoCommand::Build { .. }
|
||||||
|
| CargoCommand::Clippy { .. }
|
||||||
|
| CargoCommand::Doc { .. }
|
||||||
|
| CargoCommand::Test { .. }
|
||||||
|
| CargoCommand::Book { .. }
|
||||||
|
| CargoCommand::ExampleSize { .. } => {
|
||||||
|
let cargo_result = run_command(command, output_mode, true)?;
|
||||||
|
Ok(cargo_result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cargo command to either build or check
|
||||||
|
pub fn cargo<'c>(
|
||||||
|
globals: &Globals,
|
||||||
|
operation: BuildOrCheck,
|
||||||
|
cargoarg: &'c Option<&'c str>,
|
||||||
|
package: &'c PackageOpt,
|
||||||
|
backend: Backends,
|
||||||
|
) -> Vec<FinalRunResult<'c>> {
|
||||||
|
let runner = package
|
||||||
|
.packages()
|
||||||
|
.flat_map(|package| {
|
||||||
|
let target = backend.to_target();
|
||||||
|
let features = package.features(target, backend, globals.partial);
|
||||||
|
into_iter(features).map(move |f| (package, target, f))
|
||||||
|
})
|
||||||
|
.map(move |(package, target, features)| {
|
||||||
|
let target = target.into();
|
||||||
|
let command = match operation {
|
||||||
|
BuildOrCheck::Check => CargoCommand::Check {
|
||||||
|
cargoarg,
|
||||||
|
package: Some(package.name()),
|
||||||
|
target,
|
||||||
|
features,
|
||||||
|
mode: BuildMode::Release,
|
||||||
|
dir: None,
|
||||||
|
deny_warnings: globals.deny_warnings,
|
||||||
|
},
|
||||||
|
BuildOrCheck::Build => CargoCommand::Build {
|
||||||
|
cargoarg,
|
||||||
|
package: Some(package.name()),
|
||||||
|
target,
|
||||||
|
features,
|
||||||
|
mode: BuildMode::Release,
|
||||||
|
dir: None,
|
||||||
|
deny_warnings: globals.deny_warnings,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
(globals, command, false)
|
||||||
|
});
|
||||||
|
|
||||||
|
runner.run_and_coalesce()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cargo command to build a usage example.
|
||||||
|
///
|
||||||
|
/// The usage examples are in examples/
|
||||||
|
pub fn cargo_usage_example(
|
||||||
|
globals: &Globals,
|
||||||
|
operation: BuildOrCheck,
|
||||||
|
usage_examples: Vec<String>,
|
||||||
|
) -> Vec<FinalRunResult<'_>> {
|
||||||
|
into_iter(&usage_examples)
|
||||||
|
.map(|example| {
|
||||||
|
let path = format!("examples/{example}");
|
||||||
|
|
||||||
|
let command = match operation {
|
||||||
|
BuildOrCheck::Check => CargoCommand::Check {
|
||||||
|
cargoarg: &None,
|
||||||
|
mode: BuildMode::Release,
|
||||||
|
dir: Some(path.into()),
|
||||||
|
package: None,
|
||||||
|
target: None,
|
||||||
|
features: None,
|
||||||
|
deny_warnings: globals.deny_warnings,
|
||||||
|
},
|
||||||
|
BuildOrCheck::Build => CargoCommand::Build {
|
||||||
|
cargoarg: &None,
|
||||||
|
package: None,
|
||||||
|
target: None,
|
||||||
|
features: None,
|
||||||
|
mode: BuildMode::Release,
|
||||||
|
dir: Some(path.into()),
|
||||||
|
deny_warnings: globals.deny_warnings,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
(globals, command, false)
|
||||||
|
})
|
||||||
|
.run_and_coalesce()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cargo command to either build or check all examples
|
||||||
|
///
|
||||||
|
/// The examples are in rtic/examples
|
||||||
|
pub fn cargo_example<'c>(
|
||||||
|
globals: &Globals,
|
||||||
|
operation: BuildOrCheck,
|
||||||
|
cargoarg: &'c Option<&'c str>,
|
||||||
|
backend: Backends,
|
||||||
|
examples: &'c [String],
|
||||||
|
) -> Vec<FinalRunResult<'c>> {
|
||||||
|
let runner = into_iter(examples).map(|example| {
|
||||||
|
let features = Some(backend.to_target().and_features(backend.to_rtic_feature()));
|
||||||
|
|
||||||
|
let command = match operation {
|
||||||
|
BuildOrCheck::Check => CargoCommand::ExampleCheck {
|
||||||
|
cargoarg,
|
||||||
|
example,
|
||||||
|
target: Some(backend.to_target()),
|
||||||
|
features,
|
||||||
|
mode: BuildMode::Release,
|
||||||
|
deny_warnings: globals.deny_warnings,
|
||||||
|
},
|
||||||
|
BuildOrCheck::Build => CargoCommand::ExampleBuild {
|
||||||
|
cargoarg,
|
||||||
|
example,
|
||||||
|
target: Some(backend.to_target()),
|
||||||
|
features,
|
||||||
|
mode: BuildMode::Release,
|
||||||
|
dir: Some(PathBuf::from("./rtic")),
|
||||||
|
deny_warnings: globals.deny_warnings,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
(globals, command, false)
|
||||||
|
});
|
||||||
|
runner.run_and_coalesce()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run cargo clippy on selected package
|
||||||
|
pub fn cargo_clippy<'c>(
|
||||||
|
globals: &Globals,
|
||||||
|
cargoarg: &'c Option<&'c str>,
|
||||||
|
package: &'c PackageOpt,
|
||||||
|
backend: Backends,
|
||||||
|
) -> Vec<FinalRunResult<'c>> {
|
||||||
|
let runner = package
|
||||||
|
.packages()
|
||||||
|
.flat_map(|package| {
|
||||||
|
let target = backend.to_target();
|
||||||
|
let features = package.features(target, backend, globals.partial);
|
||||||
|
into_iter(features).map(move |f| (package, target, f))
|
||||||
|
})
|
||||||
|
.map(move |(package, target, features)| {
|
||||||
|
let command = CargoCommand::Clippy {
|
||||||
|
cargoarg,
|
||||||
|
package: Some(package.name()),
|
||||||
|
target: target.into(),
|
||||||
|
features,
|
||||||
|
deny_warnings: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
(globals, command, false)
|
||||||
|
});
|
||||||
|
|
||||||
|
runner.run_and_coalesce()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run cargo fmt on selected package
|
||||||
|
pub fn cargo_format<'c>(
|
||||||
|
globals: &Globals,
|
||||||
|
cargoarg: &'c Option<&'c str>,
|
||||||
|
package: &'c PackageOpt,
|
||||||
|
check_only: bool,
|
||||||
|
) -> Vec<FinalRunResult<'c>> {
|
||||||
|
let runner = package.packages().map(|p| {
|
||||||
|
(
|
||||||
|
globals,
|
||||||
|
CargoCommand::Format {
|
||||||
|
cargoarg,
|
||||||
|
package: Some(p.name()),
|
||||||
|
check_only,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
runner.run_and_coalesce()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run cargo doc
|
||||||
|
pub fn cargo_doc<'c>(
|
||||||
|
globals: &Globals,
|
||||||
|
cargoarg: &'c Option<&'c str>,
|
||||||
|
backend: Backends,
|
||||||
|
arguments: &'c Option<ExtraArguments>,
|
||||||
|
) -> Vec<FinalRunResult<'c>> {
|
||||||
|
let features = Some(backend.to_target().and_features(backend.to_rtic_feature()));
|
||||||
|
|
||||||
|
let command = CargoCommand::Doc {
|
||||||
|
cargoarg,
|
||||||
|
features,
|
||||||
|
arguments: arguments.clone(),
|
||||||
|
deny_warnings: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
vec![run_and_convert((globals, command, false))]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run cargo test on the selected package or all packages
|
||||||
|
///
|
||||||
|
/// If no package is specified, loop through all packages
|
||||||
|
pub fn cargo_test<'c>(
|
||||||
|
globals: &Globals,
|
||||||
|
package: &'c PackageOpt,
|
||||||
|
backend: Backends,
|
||||||
|
) -> Vec<FinalRunResult<'c>> {
|
||||||
|
package
|
||||||
|
.packages()
|
||||||
|
.map(|p| {
|
||||||
|
let meta = TestMetadata::match_package(p, backend);
|
||||||
|
(globals, meta, false)
|
||||||
|
})
|
||||||
|
.run_and_coalesce()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use mdbook to build the book
|
||||||
|
pub fn cargo_book<'c>(
|
||||||
|
globals: &Globals,
|
||||||
|
arguments: &'c Option<ExtraArguments>,
|
||||||
|
) -> Vec<FinalRunResult<'c>> {
|
||||||
|
vec![run_and_convert((
|
||||||
|
globals,
|
||||||
|
CargoCommand::Book {
|
||||||
|
arguments: arguments.clone(),
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
))]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run examples
|
||||||
|
///
|
||||||
|
/// Supports updating the expected output via the overwrite argument
|
||||||
|
pub fn qemu_run_examples<'c>(
|
||||||
|
globals: &Globals,
|
||||||
|
cargoarg: &'c Option<&'c str>,
|
||||||
|
backend: Backends,
|
||||||
|
examples: &'c [String],
|
||||||
|
overwrite: bool,
|
||||||
|
) -> Vec<FinalRunResult<'c>> {
|
||||||
|
let target = backend.to_target();
|
||||||
|
let features = Some(target.and_features(backend.to_rtic_feature()));
|
||||||
|
|
||||||
|
into_iter(examples)
|
||||||
|
.flat_map(|example| {
|
||||||
|
let target = target.into();
|
||||||
|
let dir = Some(PathBuf::from("./rtic"));
|
||||||
|
|
||||||
|
let cmd_build = CargoCommand::ExampleBuild {
|
||||||
|
cargoarg: &None,
|
||||||
|
example,
|
||||||
|
target,
|
||||||
|
features: features.clone(),
|
||||||
|
mode: BuildMode::Release,
|
||||||
|
dir: dir.clone(),
|
||||||
|
deny_warnings: globals.deny_warnings,
|
||||||
|
};
|
||||||
|
|
||||||
|
let cmd_qemu = CargoCommand::Qemu {
|
||||||
|
cargoarg,
|
||||||
|
example,
|
||||||
|
target,
|
||||||
|
features: features.clone(),
|
||||||
|
mode: BuildMode::Release,
|
||||||
|
dir,
|
||||||
|
deny_warnings: globals.deny_warnings,
|
||||||
|
};
|
||||||
|
|
||||||
|
into_iter([cmd_build, cmd_qemu])
|
||||||
|
})
|
||||||
|
.map(|cmd| (globals, cmd, overwrite))
|
||||||
|
.run_and_coalesce()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check the binary sizes of examples
|
||||||
|
pub fn build_and_check_size<'c>(
|
||||||
|
globals: &Globals,
|
||||||
|
cargoarg: &'c Option<&'c str>,
|
||||||
|
backend: Backends,
|
||||||
|
examples: &'c [String],
|
||||||
|
arguments: &'c Option<ExtraArguments>,
|
||||||
|
) -> Vec<FinalRunResult<'c>> {
|
||||||
|
let target = backend.to_target();
|
||||||
|
let features = Some(target.and_features(backend.to_rtic_feature()));
|
||||||
|
|
||||||
|
let runner = into_iter(examples)
|
||||||
|
.flat_map(|example| {
|
||||||
|
let target = target.into();
|
||||||
|
|
||||||
|
// Make sure the requested example(s) are built
|
||||||
|
let cmd_build = CargoCommand::ExampleBuild {
|
||||||
|
cargoarg: &Some("--quiet"),
|
||||||
|
example,
|
||||||
|
target,
|
||||||
|
features: features.clone(),
|
||||||
|
mode: BuildMode::Release,
|
||||||
|
dir: Some(PathBuf::from("./rtic")),
|
||||||
|
deny_warnings: globals.deny_warnings,
|
||||||
|
};
|
||||||
|
|
||||||
|
let cmd_size = CargoCommand::ExampleSize {
|
||||||
|
cargoarg,
|
||||||
|
example,
|
||||||
|
target,
|
||||||
|
features: features.clone(),
|
||||||
|
mode: BuildMode::Release,
|
||||||
|
arguments: arguments.clone(),
|
||||||
|
dir: Some(PathBuf::from("./rtic")),
|
||||||
|
deny_warnings: globals.deny_warnings,
|
||||||
|
};
|
||||||
|
|
||||||
|
[cmd_build, cmd_size]
|
||||||
|
})
|
||||||
|
.map(|cmd| (globals, cmd, false));
|
||||||
|
|
||||||
|
runner.run_and_coalesce()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_command(
|
||||||
|
command: &CargoCommand,
|
||||||
|
stderr_mode: OutputMode,
|
||||||
|
print_command_success: bool,
|
||||||
|
) -> anyhow::Result<RunResult> {
|
||||||
|
log::info!("👟 {command}");
|
||||||
|
|
||||||
|
let mut process = Command::new(command.executable());
|
||||||
|
|
||||||
|
process
|
||||||
|
.args(command.args())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(stderr_mode);
|
||||||
|
|
||||||
|
if let Some(dir) = command.chdir() {
|
||||||
|
process.current_dir(dir.canonicalize()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((k, v)) = command.extra_env() {
|
||||||
|
process.env(k, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = process.output()?;
|
||||||
|
|
||||||
|
let exit_status = result.status;
|
||||||
|
let stderr = String::from_utf8(result.stderr).unwrap_or("Not displayable".into());
|
||||||
|
let stdout = String::from_utf8(result.stdout).unwrap_or("Not displayable".into());
|
||||||
|
|
||||||
|
if command.print_stdout_intermediate() && exit_status.success() {
|
||||||
|
log::info!("\n{}", stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if print_command_success {
|
||||||
|
if exit_status.success() {
|
||||||
|
log::info!("✅ Success.")
|
||||||
|
} else {
|
||||||
|
log::error!("❌ Command failed. Run to completion for the summary.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(RunResult {
|
||||||
|
exit_status,
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
})
|
||||||
|
}
|
87
xtask/src/run/data.rs
Normal file
87
xtask/src/run/data.rs
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
use std::{
|
||||||
|
ffi::OsString,
|
||||||
|
process::{ExitStatus, Stdio},
|
||||||
|
};
|
||||||
|
|
||||||
|
use diffy::{create_patch, PatchFormatter};
|
||||||
|
|
||||||
|
use crate::cargo_command::CargoCommand;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub enum OutputMode {
|
||||||
|
PipedAndCollected,
|
||||||
|
Inherited,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<OutputMode> for Stdio {
|
||||||
|
fn from(value: OutputMode) -> Self {
|
||||||
|
match value {
|
||||||
|
OutputMode::PipedAndCollected => Stdio::piped(),
|
||||||
|
OutputMode::Inherited => Stdio::inherit(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct RunResult {
|
||||||
|
pub exit_status: ExitStatus,
|
||||||
|
pub stdout: String,
|
||||||
|
pub stderr: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum FinalRunResult<'c> {
|
||||||
|
Success(CargoCommand<'c>, RunResult),
|
||||||
|
Failed(CargoCommand<'c>, RunResult),
|
||||||
|
CommandError(CargoCommand<'c>, anyhow::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum TestRunError {
|
||||||
|
FileCmpError {
|
||||||
|
expected: String,
|
||||||
|
got: String,
|
||||||
|
},
|
||||||
|
FileError {
|
||||||
|
file: String,
|
||||||
|
},
|
||||||
|
PathConversionError(OsString),
|
||||||
|
CommandError(RunResult),
|
||||||
|
#[allow(dead_code)]
|
||||||
|
IncompatibleCommand,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Display for TestRunError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
TestRunError::FileCmpError { expected, got } => {
|
||||||
|
let patch = create_patch(expected, got);
|
||||||
|
writeln!(f, "Differing output in files.\n")?;
|
||||||
|
let pf = PatchFormatter::new().with_color();
|
||||||
|
writeln!(f, "{}", pf.fmt_patch(&patch))?;
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"See flag --overwrite-expected to create/update expected output."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
TestRunError::FileError { file } => {
|
||||||
|
write!(f, "File error on: {file}\nSee flag --overwrite-expected to create/update expected output.")
|
||||||
|
}
|
||||||
|
TestRunError::CommandError(e) => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Command failed with exit status {}: {} {}",
|
||||||
|
e.exit_status, e.stdout, e.stderr
|
||||||
|
)
|
||||||
|
}
|
||||||
|
TestRunError::PathConversionError(p) => {
|
||||||
|
write!(f, "Can't convert path from `OsString` to `String`: {p:?}")
|
||||||
|
}
|
||||||
|
TestRunError::IncompatibleCommand => {
|
||||||
|
write!(f, "Can't run that command in this context")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for TestRunError {}
|
48
xtask/src/run/iter.rs
Normal file
48
xtask/src/run/iter.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
use super::FinalRunResult;
|
||||||
|
|
||||||
|
pub use iter::*;
|
||||||
|
|
||||||
|
pub trait CoalescingRunner<'c> {
|
||||||
|
/// Run all the commands in this iterator, and coalesce the results into
|
||||||
|
/// one error (if any individual commands failed)
|
||||||
|
fn run_and_coalesce(self) -> Vec<FinalRunResult<'c>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "rayon"))]
|
||||||
|
mod iter {
|
||||||
|
use super::*;
|
||||||
|
use crate::{argument_parsing::Globals, cargo_command::*, run::run_and_convert};
|
||||||
|
|
||||||
|
pub fn into_iter<T: IntoIterator>(var: T) -> impl Iterator<Item = T::Item> {
|
||||||
|
var.into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'g, 'c, I> CoalescingRunner<'c> for I
|
||||||
|
where
|
||||||
|
I: Iterator<Item = (&'g Globals, CargoCommand<'c>, bool)>,
|
||||||
|
{
|
||||||
|
fn run_and_coalesce(self) -> Vec<FinalRunResult<'c>> {
|
||||||
|
self.map(run_and_convert).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rayon")]
|
||||||
|
mod iter {
|
||||||
|
use super::*;
|
||||||
|
use crate::{argument_parsing::Globals, cargo_command::*, run::run_and_convert};
|
||||||
|
use rayon::prelude::*;
|
||||||
|
|
||||||
|
pub fn into_iter<T: IntoParallelIterator>(var: T) -> impl ParallelIterator<Item = T::Item> {
|
||||||
|
var.into_par_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'g, 'c, I> CoalescingRunner<'c> for I
|
||||||
|
where
|
||||||
|
I: ParallelIterator<Item = (&'g Globals, CargoCommand<'c>, bool)>,
|
||||||
|
{
|
||||||
|
fn run_and_coalesce(self) -> Vec<FinalRunResult<'c>> {
|
||||||
|
self.map(run_and_convert).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
100
xtask/src/run/results.rs
Normal file
100
xtask/src/run/results.rs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
use log::{error, info, log, Level};
|
||||||
|
|
||||||
|
use crate::{argument_parsing::Globals, cargo_command::CargoCommand};
|
||||||
|
|
||||||
|
use super::data::FinalRunResult;
|
||||||
|
|
||||||
|
const TARGET: &str = "xtask::results";
|
||||||
|
|
||||||
|
pub fn handle_results(globals: &Globals, results: Vec<FinalRunResult>) -> Result<(), ()> {
|
||||||
|
let errors = results.iter().filter_map(|r| {
|
||||||
|
if let FinalRunResult::Failed(c, r) = r {
|
||||||
|
Some((c, &r.stdout, &r.stderr))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let successes = results.iter().filter_map(|r| {
|
||||||
|
if let FinalRunResult::Success(c, r) = r {
|
||||||
|
Some((c, &r.stdout, &r.stderr))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let command_errors = results.iter().filter_map(|r| {
|
||||||
|
if let FinalRunResult::CommandError(c, e) = r {
|
||||||
|
Some((c, e))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let log_stdout_stderr = |level: Level| {
|
||||||
|
move |(cmd, stdout, stderr): (&CargoCommand, &String, &String)| {
|
||||||
|
let cmd = cmd.as_cmd_string();
|
||||||
|
if !stdout.is_empty() && !stderr.is_empty() {
|
||||||
|
log!(
|
||||||
|
target: TARGET,
|
||||||
|
level,
|
||||||
|
"\n{cmd}\nStdout:\n{stdout}\nStderr:\n{stderr}"
|
||||||
|
);
|
||||||
|
} else if !stdout.is_empty() {
|
||||||
|
log!(
|
||||||
|
target: TARGET,
|
||||||
|
level,
|
||||||
|
"\n{cmd}\nStdout:\n{}",
|
||||||
|
stdout.trim_end()
|
||||||
|
);
|
||||||
|
} else if !stderr.is_empty() {
|
||||||
|
log!(
|
||||||
|
target: TARGET,
|
||||||
|
level,
|
||||||
|
"\n{cmd}\nStderr:\n{}",
|
||||||
|
stderr.trim_end()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
successes.for_each(|(cmd, stdout, stderr)| {
|
||||||
|
if globals.verbose > 0 {
|
||||||
|
info!(
|
||||||
|
target: TARGET,
|
||||||
|
"✅ Success: {cmd}\n {}",
|
||||||
|
cmd.as_cmd_string()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
info!(target: TARGET, "✅ Success: {cmd}");
|
||||||
|
}
|
||||||
|
|
||||||
|
log_stdout_stderr(Level::Debug)((cmd, stdout, stderr));
|
||||||
|
});
|
||||||
|
|
||||||
|
errors.clone().for_each(|(cmd, stdout, stderr)| {
|
||||||
|
error!(
|
||||||
|
target: TARGET,
|
||||||
|
"❌ Failed: {cmd}\n {}",
|
||||||
|
cmd.as_cmd_string()
|
||||||
|
);
|
||||||
|
log_stdout_stderr(Level::Error)((cmd, stdout, stderr));
|
||||||
|
});
|
||||||
|
|
||||||
|
command_errors.clone().for_each(|(cmd, error)| {
|
||||||
|
error!(
|
||||||
|
target: TARGET,
|
||||||
|
"❌ Failed: {cmd}\n {}\n{error}",
|
||||||
|
cmd.as_cmd_string()
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let ecount = errors.count() + command_errors.count();
|
||||||
|
if ecount != 0 {
|
||||||
|
error!(target: TARGET, "{ecount} commands failed.");
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
info!(target: TARGET, "🚀🚀🚀 All tasks succeeded 🚀🚀🚀");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue