diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..0163641 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @rust3ds/active diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml new file mode 100644 index 0000000..a86d6f6 --- /dev/null +++ b/.github/actions/setup/action.yml @@ -0,0 +1,46 @@ +name: Setup +description: Set up CI environment for Rust + 3DS development + +inputs: + toolchain: + description: The Rust toolchain to use for the steps + required: true + default: nightly + +runs: + using: composite + steps: + # https://github.com/nektos/act/issues/917#issuecomment-1074421318 + - if: ${{ env.ACT }} + shell: bash + name: Hack container for local development + run: | + curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - + sudo apt-get install -y nodejs + + - name: Setup default Rust toolchain + # Use this helper action so we get matcher support + # https://github.com/actions-rust-lang/setup-rust-toolchain/pull/15 + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + components: clippy, rustfmt, rust-src + toolchain: ${{ inputs.toolchain }} + + - name: Install build tools for host + shell: bash + run: sudo apt-get update && sudo apt-get install -y build-essential + + - name: Install cargo-3ds + uses: actions-rs/cargo@v1 + with: + command: install + # TODO: this should probably just be a released version from crates.io + # once cargo-3ds gets published somewhere... + args: >- + --git https://github.com/rust3ds/cargo-3ds + --rev 78a652fdfb01e2614a792d1a56b10c980ee1dae9 + + - name: Set PATH to include devkitARM + shell: bash + # For some reason devkitARM/bin is not part of the default PATH in the container + run: echo "${DEVKITARM}/bin" >> $GITHUB_PATH diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 102c704..20a22ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,8 @@ on: env: # https://blog.rust-lang.org/2022/06/22/sparse-registry-testing.html CARGO_UNSTABLE_SPARSE_REGISTRY: "true" + # actions-rust-lang/setup-rust-toolchain sets some default RUSTFLAGS + RUSTFLAGS: "" jobs: lint: @@ -22,41 +24,24 @@ jobs: - nightly-2023-01-13 # Check for breakage on latest nightly - nightly + # But if latest nightly fails, allow the workflow to continue continue-on-error: ${{ matrix.toolchain == 'nightly' }} runs-on: ubuntu-latest container: devkitpro/devkitarm steps: - # https://github.com/nektos/act/issues/917#issuecomment-1074421318 - - if: ${{ env.ACT }} - name: Hack container for local development - run: | - curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - - sudo apt-get install -y nodejs - - name: Checkout branch uses: actions/checkout@v2 - - name: Setup default Rust toolchain - uses: actions-rs/toolchain@v1 + - uses: ./.github/actions/setup with: - components: clippy, rustfmt, rust-src - profile: minimal toolchain: ${{ matrix.toolchain }} - default: true - - name: Install build tools for host - run: sudo apt-get update && sudo apt-get install -y build-essential - - - name: Install cargo-3ds - uses: actions-rs/cargo@v1 - with: - command: install - # TODO: this should probably just be a released version from crates.io - # once cargo-3ds gets published somewhere... - args: >- - --git https://github.com/rust3ds/cargo-3ds - --rev 7b70b6b26c4740b9a10ab85b832ee73c41142bbb + - name: Hide duplicate warnings from lint job + if: ${{ matrix.toolchain == 'nightly' }} + run: | + echo "::remove-matcher owner=clippy::" + echo "::remove-matcher owner=rustfmt::" - name: Check formatting run: cargo fmt --all --verbose -- --check @@ -68,5 +53,28 @@ jobs: # feature, but https://github.com/actions/runner/issues/2341 means we # can't have both that *and* colored output. + doctests: + strategy: + matrix: + toolchain: + - nightly-2023-01-13 + - nightly + continue-on-error: ${{ matrix.toolchain == 'nightly' }} + runs-on: ubuntu-latest + container: devkitpro/devkitarm + steps: + - name: Checkout branch + uses: actions/checkout@v2 + + - uses: ./.github/actions/setup + with: + toolchain: ${{ matrix.toolchain }} + + - name: Hide duplicated warnings from lint job + run: echo "::remove-matcher owner=clippy::" + + - name: Build doc tests + run: cargo 3ds test --doc --verbose + # TODO: it would be nice to actually build 3dsx for examples/tests, etc. # and run it somehow, but exactly how remains to be seen. diff --git a/ctru-rs/src/services/fs.rs b/ctru-rs/src/services/fs.rs index 9364bb6..e3f45b0 100644 --- a/ctru-rs/src/services/fs.rs +++ b/ctru-rs/src/services/fs.rs @@ -103,7 +103,7 @@ pub struct Fs(()); /// ```no_run /// use ctru::services::fs::Fs; /// -/// let fs = Fs::init().unwrap(); +/// let mut fs = Fs::init().unwrap(); /// let sdmc_archive = fs.sdmc().unwrap(); /// ``` pub struct Archive { @@ -123,47 +123,65 @@ pub struct Archive { /// Create a new file and write bytes to it: /// /// ```no_run +/// # use std::error::Error; +/// # fn main() -> Result<(), Box> { +/// # /// use std::io::prelude::*; /// use ctru::services::fs::{Fs, File}; /// -/// let fs = Fs::init()?; -/// let sdmc = fs.sdmc()?; +/// let mut fs = Fs::init()?; +/// let mut sdmc = fs.sdmc()?; /// -/// let mut file = File::create(&sdmc, "/foo.txt")?; +/// let mut file = File::create(&mut sdmc, "/foo.txt")?; /// file.write_all(b"Hello, world!")?; +/// # +/// # Ok(()) +/// # } /// ``` /// /// Read the contents of a file into a `String`:: /// /// ```no_run +/// # use std::error::Error; +/// # fn main() -> Result<(), Box> { +/// # /// use std::io::prelude::*; /// use ctru::services::fs::{Fs, File}; /// -/// let fs = Fs::init()?; -/// let sdmc = fs.sdmc()?; +/// let mut fs = Fs::init()?; +/// let mut sdmc = fs.sdmc()?; /// /// let mut file = File::open(&sdmc, "/foo.txt")?; /// let mut contents = String::new(); /// file.read_to_string(&mut contents)?; /// assert_eq!(contents, "Hello, world!"); +/// # +/// # Ok(()) +/// # } /// ``` /// /// It can be more efficient to read the contents of a file with a buffered /// `Read`er. This can be accomplished with `BufReader`: /// /// ```no_run +/// # use std::error::Error; +/// # fn main() -> Result<(), Box> { +/// # /// use std::io::BufReader; /// use std::io::prelude::*; /// use ctru::services::fs::{Fs, File}; /// -/// let fs = Fs::init()?; -/// let sdmc = fs.sdmc()?; +/// let mut fs = Fs::init()?; +/// let mut sdmc = fs.sdmc()?; /// /// let file = File::open(&sdmc, "/foo.txt")?; /// let mut buf_reader = BufReader::new(file); /// let mut contents = String::new(); /// buf_reader.read_to_string(&mut contents)?; /// assert_eq!(contents, "Hello, world!"); +/// # +/// # Ok(()) +/// # } /// ``` pub struct File { handle: u32, @@ -209,8 +227,8 @@ pub struct Metadata { /// ```no_run /// use ctru::services::fs::{Fs, OpenOptions}; /// -/// let fs = Fs::init().unwrap(); -/// let sdmc_archive = fs.sdmc().unwrap(); +/// let mut fs = Fs::init().unwrap(); +/// let mut sdmc_archive = fs.sdmc().unwrap(); /// let file = OpenOptions::new() /// .read(true) /// .archive(&sdmc_archive) @@ -224,8 +242,8 @@ pub struct Metadata { /// ```no_run /// use ctru::services::fs::{Fs, OpenOptions}; /// -/// let fs = Fs::init().unwrap(); -/// let sdmc_archive = fs.sdmc().unwrap(); +/// let mut fs = Fs::init().unwrap(); +/// let mut sdmc_archive = fs.sdmc().unwrap(); /// let file = OpenOptions::new() /// .read(true) /// .write(true) @@ -351,8 +369,8 @@ impl File { /// ```no_run /// use ctru::services::fs::{Fs, File}; /// - /// let fs = Fs::init().unwrap(); - /// let sdmc_archive = fs.sdmc().unwrap(); + /// let mut fs = Fs::init().unwrap(); + /// let mut sdmc_archive = fs.sdmc().unwrap(); /// let mut f = File::open(&sdmc_archive, "/foo.txt").unwrap(); /// ``` pub fn open>(arch: &Archive, path: P) -> IoResult { @@ -380,9 +398,9 @@ impl File { /// ```no_run /// use ctru::services::fs::{Fs, File}; /// - /// let fs = Fs::init().unwrap(); - /// let sdmc_archive = fs.sdmc().unwrap(); - /// let mut f = File::create(&sdmc_archive, "/foo.txt").unwrap(); + /// let mut fs = Fs::init().unwrap(); + /// let mut sdmc_archive = fs.sdmc().unwrap(); + /// let mut f = File::create(&mut sdmc_archive, "/foo.txt").unwrap(); /// ``` pub fn create>(arch: &mut Archive, path: P) -> IoResult { OpenOptions::new()