Feature documentation (#7814)

# Objective

- Fixes #1800, fixes #6984
- Alternative to #7196
- Ensure feature list is always up to date and that all are documented
- Help discovery of features

## Solution

- Use a template to update the cargo feature list
- Use the comment just above the feature declaration as the description
- Add the checks to CI
- Add the features to the base crate doc
This commit is contained in:
François 2023-02-28 14:24:47 +00:00
parent f732172c73
commit 261905f11d
12 changed files with 461 additions and 119 deletions

1
.github/bors.toml vendored
View file

@ -9,6 +9,7 @@ status = [
"run-examples-on-wasm", "run-examples-on-wasm",
"check-doc", "check-doc",
"check-missing-examples-in-docs", "check-missing-examples-in-docs",
"check-missing-features-in-docs",
# "check-unused-dependencies", # "check-unused-dependencies",
"ci", "ci",
"check-compiles", "check-compiles",

View file

@ -117,7 +117,65 @@ jobs:
owner: context.repo.owner, owner: context.repo.owner,
repo: context.repo.repo, repo: context.repo.repo,
issue_number: issue_number, issue_number: issue_number,
body: 'You added a new example but didn\'t update the readme. Please run `cargo run -p build-example-pages -- update` to update it, and commit the file change.' body: 'You added a new example but didn\'t update the readme. Please run `cargo run -p build-templated-pages -- update examples` to update it, and commit the file change.'
});
}
missing-features:
runs-on: ubuntu-latest
if: >
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'failure'
steps:
- name: 'Download artifact'
id: find-artifact
uses: actions/github-script@v6
with:
result-encoding: string
script: |
var artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{github.event.workflow_run.id }},
});
var matchArtifacts = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "missing-features"
});
if (matchArtifacts.length == 0) { return "false" }
var matchArtifact = matchArtifacts[0];
var download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
var fs = require('fs');
fs.writeFileSync('${{github.workspace}}/missing-features.zip', Buffer.from(download.data));
return "true"
- run: unzip missing-features.zip
if: ${{ steps.find-artifact.outputs.result == 'true' }}
- name: 'Comment on PR'
if: ${{ steps.find-artifact.outputs.result == 'true' }}
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
var fs = require('fs');
var issue_number = Number(fs.readFileSync('./NR'));
if (fs.existsSync('./missing-features')) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: 'You added a new feature but didn\'t add a description for it. Please update the root Cargo.toml file.'
});
}
if (fs.existsSync('./missing-update')) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: 'You added a new feature but didn\'t update the readme. Please run `cargo run -p build-templated-pages -- update features` to update it, and commit the file change.'
}); });
} }

View file

@ -257,14 +257,14 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: check for missing metadata - name: check for missing metadata
id: missing-metadata id: missing-metadata
run: cargo run -p build-example-pages -- check-missing run: cargo run -p build-templated-pages -- check-missing examples
- name: check for missing update - name: check for missing update
id: missing-update id: missing-update
run: cargo run -p build-example-pages -- update run: cargo run -p build-templated-pages -- update examples
- name: Check for modified files - name: Check for modified files
run: | run: |
echo "if this step fails, run the following command and commit the changed file on your PR." echo "if this step fails, run the following command and commit the changed file on your PR."
echo " > cargo run -p build-example-pages -- update" echo " > cargo run -p build-templated-pages -- update examples"
git diff --quiet HEAD -- git diff --quiet HEAD --
- name: Save PR number - name: Save PR number
if: ${{ failure() && github.event_name == 'pull_request' }} if: ${{ failure() && github.event_name == 'pull_request' }}
@ -283,6 +283,39 @@ jobs:
name: missing-examples name: missing-examples
path: missing-examples/ path: missing-examples/
check-missing-features-in-docs:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v3
- name: check for missing features
id: missing-features
run: cargo run -p build-templated-pages -- check-missing features
- name: check for missing update
id: missing-update
run: cargo run -p build-templated-pages -- update features
- name: Check for modified files
run: |
echo "if this step fails, run the following command and commit the changed file on your PR."
echo " > cargo run -p build-templated-pages -- update features"
git diff --quiet HEAD --
- name: Save PR number
if: ${{ failure() && github.event_name == 'pull_request' }}
run: |
mkdir -p ./missing-features
echo ${{ github.event.number }} > ./missing-features/NR
- name: log failed task - missing features
if: ${{ failure() && github.event_name == 'pull_request' && steps.missing-features.conclusion == 'failure' }}
run: touch ./missing-features/missing-features
- name: log failed task - missing update
if: ${{ failure() && github.event_name == 'pull_request' && steps.missing-update.conclusion == 'failure' }}
run: touch ./missing-features/missing-update
- uses: actions/upload-artifact@v2
if: ${{ failure() && github.event_name == 'pull_request' }}
with:
name: missing-features
path: missing-features/
check-unused-dependencies: check-unused-dependencies:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 30 timeout-minutes: 30

View file

@ -22,7 +22,7 @@ members = [
"crates/*", "crates/*",
"examples/mobile", "examples/mobile",
"tools/ci", "tools/ci",
"tools/build-example-pages", "tools/build-templated-pages",
"tools/build-wasm-example", "tools/build-wasm-example",
"errors", "errors",
] ]
@ -56,62 +56,136 @@ default = [
# Force dynamic linking, which improves iterative compile times # Force dynamic linking, which improves iterative compile times
dynamic_linking = ["bevy_dylib", "bevy_internal/dynamic_linking"] dynamic_linking = ["bevy_dylib", "bevy_internal/dynamic_linking"]
# Optional bevy crates # Provides animation functionality
bevy_animation = ["bevy_internal/bevy_animation"] bevy_animation = ["bevy_internal/bevy_animation"]
# Provides asset functionality
bevy_asset = ["bevy_internal/bevy_asset"] bevy_asset = ["bevy_internal/bevy_asset"]
# Provides audio functionality
bevy_audio = ["bevy_internal/bevy_audio"] bevy_audio = ["bevy_internal/bevy_audio"]
# Provides cameras and other basic render pipeline features
bevy_core_pipeline = ["bevy_internal/bevy_core_pipeline"] bevy_core_pipeline = ["bevy_internal/bevy_core_pipeline"]
# Plugin for dynamic loading (using [libloading](https://crates.io/crates/libloading))
bevy_dynamic_plugin = ["bevy_internal/bevy_dynamic_plugin"] bevy_dynamic_plugin = ["bevy_internal/bevy_dynamic_plugin"]
# Adds gamepad support
bevy_gilrs = ["bevy_internal/bevy_gilrs"] bevy_gilrs = ["bevy_internal/bevy_gilrs"]
# [glTF](https://www.khronos.org/gltf/) support
bevy_gltf = ["bevy_internal/bevy_gltf"] bevy_gltf = ["bevy_internal/bevy_gltf"]
# Adds PBR rendering
bevy_pbr = ["bevy_internal/bevy_pbr"] bevy_pbr = ["bevy_internal/bevy_pbr"]
# Provides rendering functionality
bevy_render = ["bevy_internal/bevy_render"] bevy_render = ["bevy_internal/bevy_render"]
# Provides scene functionality
bevy_scene = ["bevy_internal/bevy_scene"] bevy_scene = ["bevy_internal/bevy_scene"]
# Provides sprite functionality
bevy_sprite = ["bevy_internal/bevy_sprite"] bevy_sprite = ["bevy_internal/bevy_sprite"]
# Provides text functionality
bevy_text = ["bevy_internal/bevy_text"] bevy_text = ["bevy_internal/bevy_text"]
# A custom ECS-driven UI framework
bevy_ui = ["bevy_internal/bevy_ui"] bevy_ui = ["bevy_internal/bevy_ui"]
# winit window and input backend
bevy_winit = ["bevy_internal/bevy_winit"] bevy_winit = ["bevy_internal/bevy_winit"]
# Tracing features # Tracing support, saving a file in Chrome Tracing format
trace_chrome = ["trace", "bevy_internal/trace_chrome"] trace_chrome = ["trace", "bevy_internal/trace_chrome"]
# Tracing support, exposing a port for Tracy
trace_tracy = ["trace", "bevy_internal/trace_tracy"] trace_tracy = ["trace", "bevy_internal/trace_tracy"]
# Tracing support
trace = ["bevy_internal/trace"] trace = ["bevy_internal/trace"]
# Save a trace of all wgpu calls
wgpu_trace = ["bevy_internal/wgpu_trace"] wgpu_trace = ["bevy_internal/wgpu_trace"]
# Image format support for texture loading (PNG and HDR are enabled by default) # EXR image format support
exr = ["bevy_internal/exr"] exr = ["bevy_internal/exr"]
# HDR image format support
hdr = ["bevy_internal/hdr"] hdr = ["bevy_internal/hdr"]
# PNG image format support
png = ["bevy_internal/png"] png = ["bevy_internal/png"]
# TGA image format support
tga = ["bevy_internal/tga"] tga = ["bevy_internal/tga"]
# JPEG image format support
jpeg = ["bevy_internal/jpeg"] jpeg = ["bevy_internal/jpeg"]
# BMP image format support
bmp = ["bevy_internal/bmp"] bmp = ["bevy_internal/bmp"]
# Basis Universal compressed texture support
basis-universal = ["bevy_internal/basis-universal"] basis-universal = ["bevy_internal/basis-universal"]
# DDS compressed texture support
dds = ["bevy_internal/dds"] dds = ["bevy_internal/dds"]
# KTX2 compressed texture support
ktx2 = ["bevy_internal/ktx2"] ktx2 = ["bevy_internal/ktx2"]
# For ktx2 supercompression
# For KTX2 supercompression
zlib = ["bevy_internal/zlib"] zlib = ["bevy_internal/zlib"]
# For KTX2 supercompression
zstd = ["bevy_internal/zstd"] zstd = ["bevy_internal/zstd"]
# Audio format support (vorbis is enabled by default) # FLAC audio format support
flac = ["bevy_internal/flac"] flac = ["bevy_internal/flac"]
# MP3 audio format support
mp3 = ["bevy_internal/mp3"] mp3 = ["bevy_internal/mp3"]
# OGG/VORBIS audio format support
vorbis = ["bevy_internal/vorbis"] vorbis = ["bevy_internal/vorbis"]
# WAV audio format support
wav = ["bevy_internal/wav"] wav = ["bevy_internal/wav"]
# AAC audio format support (through symphonia)
symphonia-aac = ["bevy_internal/symphonia-aac"] symphonia-aac = ["bevy_internal/symphonia-aac"]
# AAC, FLAC, MP3, MP4, OGG/VORBIS, and WAV audio formats support (through symphonia)
symphonia-all = ["bevy_internal/symphonia-all"] symphonia-all = ["bevy_internal/symphonia-all"]
# FLAC audio format support (through symphonia)
symphonia-flac = ["bevy_internal/symphonia-flac"] symphonia-flac = ["bevy_internal/symphonia-flac"]
# MP4 audio format support (through symphonia)
symphonia-isomp4 = ["bevy_internal/symphonia-isomp4"] symphonia-isomp4 = ["bevy_internal/symphonia-isomp4"]
# MP3 audio format support (through symphonia)
symphonia-mp3 = ["bevy_internal/symphonia-mp3"] symphonia-mp3 = ["bevy_internal/symphonia-mp3"]
# OGG/VORBIS audio format support (through symphonia)
symphonia-vorbis = ["bevy_internal/symphonia-vorbis"] symphonia-vorbis = ["bevy_internal/symphonia-vorbis"]
# WAV audio format support (through symphonia)
symphonia-wav = ["bevy_internal/symphonia-wav"] symphonia-wav = ["bevy_internal/symphonia-wav"]
# Enable watching file system for asset hot reload # Enable watching file system for asset hot reload
filesystem_watcher = ["bevy_internal/filesystem_watcher"] filesystem_watcher = ["bevy_internal/filesystem_watcher"]
# Enable serialization support through serde
serialize = ["bevy_internal/serialize"] serialize = ["bevy_internal/serialize"]
# Display server protocol support (X11 is enabled by default) # Wayland display server support
wayland = ["bevy_internal/wayland"] wayland = ["bevy_internal/wayland"]
# X11 display server support
x11 = ["bevy_internal/x11"] x11 = ["bevy_internal/x11"]
# Enable rendering of font glyphs using subpixel accuracy # Enable rendering of font glyphs using subpixel accuracy
@ -124,16 +198,15 @@ bevy_ci_testing = ["bevy_internal/bevy_ci_testing"]
debug_asset_server = ["bevy_internal/debug_asset_server"] debug_asset_server = ["bevy_internal/debug_asset_server"]
# Enable animation support, and glTF animation loading # Enable animation support, and glTF animation loading
animation = ["bevy_internal/animation"] animation = ["bevy_internal/animation", "bevy_animation"]
# Enable using a shared stdlib for cxx on Android. # Enable using a shared stdlib for cxx on Android
android_shared_stdcxx = ["bevy_internal/android_shared_stdcxx"] android_shared_stdcxx = ["bevy_internal/android_shared_stdcxx"]
# Enable detailed trace event logging. # Enable detailed trace event logging. These trace events are expensive even when off, thus they require compile time opt-in
# These trace events are expensive even when off, thus they require compile time opt-in.
detailed_trace = ["bevy_internal/detailed_trace"] detailed_trace = ["bevy_internal/detailed_trace"]
# Include tonemapping LUT KTX2 files. # Include tonemapping Look Up Tables KTX2 files
tonemapping_luts = ["bevy_internal/tonemapping_luts"] tonemapping_luts = ["bevy_internal/tonemapping_luts"]
[dependencies] [dependencies]
@ -1267,7 +1340,7 @@ category = "Scene"
wasm = false wasm = false
# Shaders # Shaders
[[package.metadata.category]] [[package.metadata.example_category]]
name = "Shaders" name = "Shaders"
description = """ description = """
These examples demonstrate how to implement different shaders in user code. These examples demonstrate how to implement different shaders in user code.
@ -1399,7 +1472,7 @@ category = "Shaders"
wasm = false wasm = false
# Stress tests # Stress tests
[[package.metadata.category]] [[package.metadata.example_category]]
name = "Stress Tests" name = "Stress Tests"
description = """ description = """
These examples are used to test the performance and stability of various parts of the engine in an isolated way. These examples are used to test the performance and stability of various parts of the engine in an isolated way.

View file

@ -0,0 +1,21 @@
<!-- MD041 - This file will be included in docs and should not start with a top header -->
<!-- markdownlint-disable-file MD041 -->
## Cargo Features
Bevy exposes many features to customise the engine. Enabling them add functionalities but often come at the cost of longer compilation times and extra dependencies.
### Default Features
The default feature set enables most of the expected features of a game engine, like rendering in both 2D and 3D, asset loading, audio and UI. To help reduce compilation time, consider disabling default features and enabling only those you need.
|feature name|description|
|-|-|
{% for feature in features %}{% if feature.is_default %}|{{ feature.name }}|{{ feature.description }}|
{% endif %}{% endfor %}
### Optional Features
|feature name|description|
|-|-|
{% for feature in features %}{% if feature.is_default == False %}|{{ feature.name }}|{{ feature.description }}|
{% endif %}{% endfor %}

View file

@ -1,53 +1,70 @@
# Cargo Features <!-- MD041 - This file will be included in docs and should not start with a top header -->
<!-- markdownlint-disable-file MD041 -->
## Default Features ## Cargo Features
Bevy exposes many features to customise the engine. Enabling them add functionalities but often come at the cost of longer compilation times and extra dependencies.
### Default Features
The default feature set enables most of the expected features of a game engine, like rendering in both 2D and 3D, asset loading, audio and UI. To help reduce compilation time, consider disabling default features and enabling only those you need.
|feature name|description| |feature name|description|
|-|-| |-|-|
|animation|Animation support and glTF animation loading.| |android_shared_stdcxx|Enable using a shared stdlib for cxx on Android|
|bevy_asset|Provides asset functionality for Bevy Engine.| |animation|Enable animation support, and glTF animation loading|
|bevy_audio|Audio support. Support for all audio formats depends on this.| |bevy_animation|Provides animation functionality|
|bevy_gilrs|Adds gamepad support.| |bevy_asset|Provides asset functionality|
|bevy_gltf|[glTF](https://www.khronos.org/gltf/) support.| |bevy_audio|Provides audio functionality|
|bevy_scene|Provides scene functionality for Bevy Engine.| |bevy_core_pipeline|Provides cameras and other basic render pipeline features|
|bevy_winit|GUI support.| |bevy_gilrs|Adds gamepad support|
|render|The render pipeline and all render related plugins.| |bevy_gltf|[glTF](https://www.khronos.org/gltf/) support|
|png|PNG picture format support.| |bevy_pbr|Adds PBR rendering|
|hdr|[HDR](https://en.wikipedia.org/wiki/High_dynamic_range) support.| |bevy_render|Provides rendering functionality|
|vorbis|Ogg Vorbis audio format support.| |bevy_scene|Provides scene functionality|
|x11|Make GUI applications use X11 protocol. You could enable wayland feature to override this.| |bevy_sprite|Provides sprite functionality|
|filesystem_watcher|Enable watching the file system for asset hot reload| |bevy_text|Provides text functionality|
|bevy_ui|A custom ECS-driven UI framework|
|bevy_winit|winit window and input backend|
|filesystem_watcher|Enable watching file system for asset hot reload|
|hdr|HDR image format support|
|ktx2|KTX2 compressed texture support|
|png|PNG image format support|
|tonemapping_luts|Include tonemapping Look Up Tables KTX2 files|
|vorbis|OGG/VORBIS audio format support|
|x11|X11 display server support|
|zstd|For KTX2 supercompression|
## Optional Features ### Optional Features
|feature name|description| |feature name|description|
|-|-| |-|-|
|bevy_dynamic_plugin|Plugin for dynamic loading (using [libloading](https://crates.io/crates/libloading)).| |basis-universal|Basis Universal compressed texture support|
|dynamic_linking|Forces bevy to be dynamically linked, which improves iterative compile times.| |bevy_ci_testing|Enable systems that allow for automated testing on CI|
|trace|Enables system tracing.| |bevy_dynamic_plugin|Plugin for dynamic loading (using [libloading](https://crates.io/crates/libloading))|
|trace_chrome|Enables [tracing-chrome](https://github.com/thoren-d/tracing-chrome) as bevy_log output. This allows you to visualize system execution.| |bmp|BMP image format support|
|trace_tracy|Enables [Tracy](https://github.com/wolfpld/tracy) as bevy_log output. This allows `Tracy` to connect to and capture profiling data as well as visualize system execution in real-time, present statistics about system execution times, and more.| |dds|DDS compressed texture support|
|wgpu_trace|For tracing wgpu.| |debug_asset_server|Enable the "debug asset server" for hot reloading internal assets|
|dds|DDS picture format support.| |detailed_trace|Enable detailed trace event logging. These trace events are expensive even when off, thus they require compile time opt-in|
|ktx2|KTX2 picture format support.| |dynamic_linking|Force dynamic linking, which improves iterative compile times|
|zlib|KTX2 Zlib supercompression support.| |exr|EXR image format support|
|zstd|KTX2 Zstandard supercompression support.| |flac|FLAC audio format support|
|basis-universal|Basis Universal picture format support and, if the `ktx2` feature is enabled, also KTX2 UASTC picture format transcoding support.| |jpeg|JPEG image format support|
|tga|TGA picture format support.| |mp3|MP3 audio format support|
|jpeg|JPEG picture format support.| |serialize|Enable serialization support through serde|
|bmp|BMP picture format support.| |subpixel_glyph_atlas|Enable rendering of font glyphs using subpixel accuracy|
|flac|FLAC audio format support. It's included in bevy_audio feature.| |symphonia-aac|AAC audio format support (through symphonia)|
|mp3|MP3 audio format support.| |symphonia-all|AAC, FLAC, MP3, MP4, OGG/VORBIS, and WAV audio formats support (through symphonia)|
|wav|WAV audio format support.| |symphonia-flac|FLAC audio format support (through symphonia)|
|symphonia-aac|AAC audio format support by Symphonia. For more details, see `symphonia-all`.| |symphonia-isomp4|MP4 audio format support (through symphonia)|
|symphonia-all|AAC, FLAC, MP4, MP3, Vorbis, and WAV support by Symphonia. Add support for parsing multiple file formats using a single crate instead of compiling different crates. The other non-`symphonia` features are disabled when its corresponding `symphonia` feature is enabled. [Link to `symphonia` documentation](https://docs.rs/symphonia/latest/symphonia/). More information about this topic can be found [here](https://github.com/bevyengine/bevy/pull/6388#discussion_r1009622883) | |symphonia-mp3|MP3 audio format support (through symphonia)|
|symphonia-flac|FLAC audio format support by Symphonia. For more details, see `symphonia-all`.| |symphonia-vorbis|OGG/VORBIS audio format support (through symphonia)|
|symphonia-isomp4|MP4 audio format support by Symphonia. For more details, see `symphonia-all`.| |symphonia-wav|WAV audio format support (through symphonia)|
|symphonia-mp3|MP3 audio format support by Symphonia. For more details, see `symphonia-all`.| |tga|TGA image format support|
|symphonia-vorbis|Vorbis audio format support by Symphonia. For more details, see `symphonia-all`.| |trace|Tracing support|
|symphonia-wav|WAV audio format support by Symphonia. For more details, see `symphonia-all`.| |trace_chrome|Tracing support, saving a file in Chrome Tracing format|
|serialize|Enables serialization of `bevy_input` types.| |trace_tracy|Tracing support, exposing a port for Tracy|
|wayland|Enable this to use Wayland display server protocol other than X11.| |wav|WAV audio format support|
|subpixel_glyph_atlas|Enable this to cache glyphs using subpixel accuracy. This increases texture memory usage as each position requires a separate sprite in the glyph atlas, but provide more accurate character spacing.| |wayland|Wayland display server support|
|bevy_ci_testing|Used for running examples in CI.| |wgpu_trace|Save a trace of all wgpu calls|
|debug_asset_server|Enabling this turns on "hot reloading" of built in assets, such as shaders.| |zlib|For KTX2 supercompression|

View file

@ -10,6 +10,7 @@
//! community](https://bevyengine.org/community/) if you have any questions or ideas! //! community](https://bevyengine.org/community/) if you have any questions or ideas!
//! //!
//! ## Example //! ## Example
//!
//! Here is a simple "Hello World" Bevy app: //! Here is a simple "Hello World" Bevy app:
//! ``` //! ```
//! use bevy::prelude::*; //! use bevy::prelude::*;
@ -28,7 +29,8 @@
//! Don't let the simplicity of the example above fool you. Bevy is a [fully featured game engine](https://bevyengine.org) //! Don't let the simplicity of the example above fool you. Bevy is a [fully featured game engine](https://bevyengine.org)
//! and it gets more powerful every day! //! and it gets more powerful every day!
//! //!
//! ### This Crate //! ## This Crate
//!
//! The `bevy` crate is just a container crate that makes it easier to consume Bevy subcrates. //! The `bevy` crate is just a container crate that makes it easier to consume Bevy subcrates.
//! The defaults provide a "full" engine experience, but you can easily enable / disable features //! The defaults provide a "full" engine experience, but you can easily enable / disable features
//! in your project's `Cargo.toml` to meet your specific needs. See Bevy's `Cargo.toml` for a full //! in your project's `Cargo.toml` to meet your specific needs. See Bevy's `Cargo.toml` for a full
@ -37,7 +39,7 @@
//! If you prefer, you can also consume the individual bevy crates directly. //! If you prefer, you can also consume the individual bevy crates directly.
//! Each module in the root of this crate, except for the prelude, can be found on crates.io //! Each module in the root of this crate, except for the prelude, can be found on crates.io
//! with `bevy_` appended to the front, e.g. `app` -> [`bevy_app`](https://docs.rs/bevy_app/*/bevy_app/). //! with `bevy_` appended to the front, e.g. `app` -> [`bevy_app`](https://docs.rs/bevy_app/*/bevy_app/).
#![doc = include_str!("../docs/cargo_features.md")]
#![doc( #![doc(
html_logo_url = "https://bevyengine.org/assets/icon.png", html_logo_url = "https://bevyengine.org/assets/icon.png",
html_favicon_url = "https://bevyengine.org/assets/icon.png" html_favicon_url = "https://bevyengine.org/assets/icon.png"

View file

@ -1,8 +1,8 @@
[package] [package]
name = "build-example-pages" name = "build-templated-pages"
version = "0.9.0" version = "0.9.0"
edition = "2021" edition = "2021"
description = "handle examples in Bevy" description = "handle templated pages in Bevy repository"
publish = false publish = false
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"

View file

@ -1,60 +1,10 @@
use std::{cmp::Ordering, collections::HashMap, fs::File}; use std::{cmp::Ordering, collections::HashMap, fs::File};
use bitflags::bitflags;
use serde::Serialize; use serde::Serialize;
use tera::{Context, Tera}; use tera::{Context, Tera};
use toml_edit::Document; use toml_edit::Document;
bitflags! { use crate::Command;
struct Command: u32 {
const CHECK_MISSING = 0b00000001;
const UPDATE = 0b00000010;
}
}
fn main() {
let what_to_run = match std::env::args().nth(1).as_deref() {
Some("check-missing") => Command::CHECK_MISSING,
Some("update") => Command::UPDATE,
_ => Command::all(),
};
let examples = parse_examples(what_to_run.contains(Command::CHECK_MISSING));
if what_to_run.contains(Command::UPDATE) {
let categories = parse_categories();
let examples_by_category: HashMap<String, Category> = examples
.into_iter()
.fold(HashMap::<String, Vec<Example>>::new(), |mut v, ex| {
v.entry(ex.category.clone()).or_default().push(ex);
v
})
.into_iter()
.map(|(key, mut examples)| {
examples.sort();
let description = categories.get(&key).cloned();
(
key,
Category {
description,
examples,
},
)
})
.collect();
let mut context = Context::new();
context.insert("all_examples", &examples_by_category);
Tera::new("examples/*.md.tpl")
.expect("error parsing template")
.render_to(
"README.md.tpl",
&context,
File::create("examples/README.md").expect("error creating file"),
)
.expect("error rendering template");
}
}
#[derive(Debug, Serialize, PartialEq, Eq)] #[derive(Debug, Serialize, PartialEq, Eq)]
struct Category { struct Category {
@ -138,7 +88,7 @@ fn parse_categories() -> HashMap<String, String> {
.unwrap() .unwrap()
.get("metadata") .get("metadata")
.as_ref() .as_ref()
.unwrap()["category"] .unwrap()["example_category"]
.clone() .clone()
.as_array_of_tables() .as_array_of_tables()
.unwrap() .unwrap()
@ -151,3 +101,41 @@ fn parse_categories() -> HashMap<String, String> {
}) })
.collect() .collect()
} }
pub(crate) fn check(what_to_run: Command) {
let examples = parse_examples(what_to_run.contains(Command::CHECK_MISSING));
if what_to_run.contains(Command::UPDATE) {
let categories = parse_categories();
let examples_by_category: HashMap<String, Category> = examples
.into_iter()
.fold(HashMap::<String, Vec<Example>>::new(), |mut v, ex| {
v.entry(ex.category.clone()).or_default().push(ex);
v
})
.into_iter()
.map(|(key, mut examples)| {
examples.sort();
let description = categories.get(&key).cloned();
(
key,
Category {
description,
examples,
},
)
})
.collect();
let mut context = Context::new();
context.insert("all_examples", &examples_by_category);
Tera::new("docs-template/*.md.tpl")
.expect("error parsing template")
.render_to(
"EXAMPLE_README.md.tpl",
&context,
File::create("examples/README.md").expect("error creating file"),
)
.expect("error rendering template");
}
}

View file

@ -0,0 +1,110 @@
use std::{cmp::Ordering, fs::File};
use serde::Serialize;
use tera::{Context, Tera};
use toml_edit::Document;
use crate::Command;
#[derive(Debug, Serialize, PartialEq, Eq)]
struct Feature {
name: String,
description: String,
is_default: bool,
}
impl Ord for Feature {
fn cmp(&self, other: &Self) -> Ordering {
self.name.cmp(&other.name)
}
}
impl PartialOrd for Feature {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
fn parse_features(panic_on_missing: bool) -> Vec<Feature> {
let manifest_file = std::fs::read_to_string("Cargo.toml").unwrap();
let manifest = manifest_file.parse::<Document>().unwrap();
let features = manifest["features"].as_table().unwrap();
let default: Vec<_> = features
.get("default")
.unwrap()
.as_array()
.unwrap()
.iter()
.flat_map(|v| {
std::iter::once(v.as_str().unwrap().to_string()).chain(
features
.get(v.as_str().unwrap())
.unwrap()
.as_array()
.unwrap()
.iter()
.map(|v| v.as_str().unwrap().to_string()),
)
})
.collect();
features
.get_values()
.iter()
.flat_map(|(key, _)| {
let key = key[0];
if key == "default" {
None
} else {
let name = key
.as_repr()
.unwrap()
.as_raw()
.as_str()
.unwrap()
.to_string();
if let Some(description) = key.decor().prefix() {
let description = description.as_str().unwrap().to_string();
if !description.starts_with("\n# ") || !description.ends_with('\n') {
panic!("Missing description for feature {name}");
}
let description = description
.strip_prefix("\n# ")
.unwrap()
.strip_suffix('\n')
.unwrap()
.to_string();
Some(Feature {
is_default: default.contains(&name),
name,
description,
})
} else if panic_on_missing {
panic!("Missing description for feature {name}");
} else {
None
}
}
})
.collect()
}
pub(crate) fn check(what_to_run: Command) {
let mut features = parse_features(what_to_run.contains(Command::CHECK_MISSING));
features.sort();
if what_to_run.contains(Command::UPDATE) {
let mut context = Context::new();
context.insert("features", &features);
Tera::new("docs-template/*.md.tpl")
.expect("error parsing template")
.render_to(
"features.md.tpl",
&context,
File::create("docs/cargo_features.md").expect("error creating file"),
)
.expect("error rendering template");
}
}

View file

@ -0,0 +1,39 @@
use bitflags::bitflags;
mod examples;
mod features;
bitflags! {
struct Command: u32 {
const CHECK_MISSING = 0b00000001;
const UPDATE = 0b00000010;
}
}
bitflags! {
struct Target: u32 {
const EXAMPLES = 0b00000001;
const FEATURES = 0b00000010;
}
}
fn main() {
let what_to_run = match std::env::args().nth(1).as_deref() {
Some("check-missing") => Command::CHECK_MISSING,
Some("update") => Command::UPDATE,
_ => Command::all(),
};
let target = match std::env::args().nth(2).as_deref() {
Some("examples") => Target::EXAMPLES,
Some("features") => Target::FEATURES,
_ => Target::all(),
};
if target.contains(Target::EXAMPLES) {
examples::check(what_to_run);
}
if target.contains(Target::FEATURES) {
features::check(what_to_run);
}
}