example showcase - pagination and can build for WebGL2 (#9168)

# Objective

- Building all examples at once in CI takes too long
- Tool can only build for WebGPU

## Solution

- Add pagination to commands
- Add option to build examples for WebGL2
- Add option to build Zola files for WebGL2
This commit is contained in:
François 2023-07-18 00:20:22 +02:00 committed by GitHub
parent 9ad546ecec
commit ff89968ffc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 118 additions and 31 deletions

View File

@ -4,7 +4,7 @@ use clap::{Parser, ValueEnum};
use xshell::{cmd, Shell}; use xshell::{cmd, Shell};
#[derive(Debug, Copy, Clone, ValueEnum)] #[derive(Debug, Copy, Clone, ValueEnum)]
enum Api { enum WebApi {
Webgl2, Webgl2,
Webgpu, Webgpu,
} }
@ -26,9 +26,9 @@ struct Args {
/// Stop after this number of frames /// Stop after this number of frames
frames: Option<usize>, frames: Option<usize>,
#[arg(value_enum, short, long, default_value_t = Api::Webgl2)] #[arg(value_enum, short, long, default_value_t = WebApi::Webgl2)]
/// Browser API to use for rendering /// Browser API to use for rendering
api: Api, api: WebApi,
#[arg(short, long)] #[arg(short, long)]
/// Optimize the wasm file for size with wasm-opt /// Optimize the wasm file for size with wasm-opt
@ -50,8 +50,8 @@ fn main() {
} }
match cli.api { match cli.api {
Api::Webgl2 => (), WebApi::Webgl2 => (),
Api::Webgpu => { WebApi::Webgpu => {
features.push("animation"); features.push("animation");
features.push("bevy_asset"); features.push("bevy_asset");
features.push("bevy_audio"); features.push("bevy_audio");
@ -95,7 +95,7 @@ fn main() {
sh, sh,
"cargo build {parameters...} --profile release --target wasm32-unknown-unknown --example {example}" "cargo build {parameters...} --profile release --target wasm32-unknown-unknown --example {example}"
); );
if matches!(cli.api, Api::Webgpu) { if matches!(cli.api, WebApi::Webgpu) {
cmd = cmd.env("RUSTFLAGS", "--cfg=web_sys_unstable_apis"); cmd = cmd.env("RUSTFLAGS", "--cfg=web_sys_unstable_apis");
} }
cmd.run().expect("Error building example"); cmd.run().expect("Error building example");

View File

@ -1,5 +1,6 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
fmt::Display,
fs::{self, File}, fs::{self, File},
io::Write, io::Write,
path::{Path, PathBuf}, path::{Path, PathBuf},
@ -8,7 +9,7 @@ use std::{
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use clap::Parser; use clap::{error::ErrorKind, CommandFactory, Parser, ValueEnum};
use pbr::ProgressBar; use pbr::ProgressBar;
use toml_edit::Document; use toml_edit::Document;
use xshell::{cmd, Shell}; use xshell::{cmd, Shell};
@ -21,6 +22,13 @@ struct Args {
#[command(subcommand)] #[command(subcommand)]
action: Action, action: Action,
#[arg(long)]
/// Pagination control - page number. To use with --per-page
page: Option<usize>,
#[arg(long)]
/// Pagination control - number of examples per page. To use with --page
per_page: Option<usize>,
} }
#[derive(clap::Subcommand, Debug)] #[derive(clap::Subcommand, Debug)]
@ -44,9 +52,13 @@ enum Action {
#[arg(long)] #[arg(long)]
/// Path to the folder where the content should be created /// Path to the folder where the content should be created
content_folder: String, content_folder: String,
#[arg(value_enum, long, default_value_t = WebApi::Webgl2)]
/// Which API to use for rendering
api: WebApi,
}, },
/// BUild the examples in wasm / WebGPU /// Build the examples in wasm
BuildWebGPUExamples { BuildWasmExamples {
#[arg(long)] #[arg(long)]
/// Path to the folder where the content should be created /// Path to the folder where the content should be created
content_folder: String, content_folder: String,
@ -58,12 +70,40 @@ enum Action {
#[arg(long)] #[arg(long)]
/// Optimize the wasm file for size with wasm-opt /// Optimize the wasm file for size with wasm-opt
optimize_size: bool, optimize_size: bool,
#[arg(value_enum, long)]
/// Which API to use for rendering
api: WebApi,
}, },
} }
#[derive(Debug, Copy, Clone, ValueEnum)]
enum WebApi {
Webgl2,
Webgpu,
}
impl Display for WebApi {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
WebApi::Webgl2 => write!(f, "webgl2"),
WebApi::Webgpu => write!(f, "webgpu"),
}
}
}
fn main() { fn main() {
let cli = Args::parse(); let cli = Args::parse();
if cli.page.is_none() != cli.per_page.is_none() {
let mut cmd = Args::command();
cmd.error(
ErrorKind::MissingRequiredArgument,
"page and per-page must be used together",
)
.exit();
}
let profile = cli.profile; let profile = cli.profile;
match cli.action { match cli.action {
@ -106,7 +146,16 @@ fn main() {
} }
} }
for to_run in examples_to_run { let work_to_do = || {
examples_to_run
.iter()
.skip(cli.page.unwrap_or(0) * cli.per_page.unwrap_or(0))
.take(cli.per_page.unwrap_or(usize::MAX))
};
let mut pb = ProgressBar::new(work_to_do().count() as u64);
for to_run in work_to_do() {
let sh = Shell::new().unwrap(); let sh = Shell::new().unwrap();
let example = &to_run.technical_name; let example = &to_run.technical_name;
let extra_parameters = extra_parameters.clone(); let extra_parameters = extra_parameters.clone();
@ -143,7 +192,9 @@ fn main() {
println!("took {duration:?}"); println!("took {duration:?}");
thread::sleep(Duration::from_secs(1)); thread::sleep(Duration::from_secs(1));
pb.inc();
} }
pb.finish_print("done");
if failed_examples.is_empty() { if failed_examples.is_empty() {
println!("All examples passed!"); println!("All examples passed!");
} else { } else {
@ -157,7 +208,10 @@ fn main() {
exit(1); exit(1);
} }
} }
Action::BuildWebsiteList { content_folder } => { Action::BuildWebsiteList {
content_folder,
api,
} => {
let examples_to_run = parse_examples(); let examples_to_run = parse_examples();
let root_path = Path::new(&content_folder); let root_path = Path::new(&content_folder);
@ -165,9 +219,10 @@ fn main() {
let _ = fs::create_dir_all(root_path); let _ = fs::create_dir_all(root_path);
let mut index = File::create(root_path.join("_index.md")).unwrap(); let mut index = File::create(root_path.join("_index.md")).unwrap();
index if matches!(api, WebApi::Webgpu) {
.write_all( index
"+++ .write_all(
"+++
title = \"Bevy Examples in WebGPU\" title = \"Bevy Examples in WebGPU\"
template = \"examples-webgpu.html\" template = \"examples-webgpu.html\"
sort_by = \"weight\" sort_by = \"weight\"
@ -175,9 +230,24 @@ sort_by = \"weight\"
[extra] [extra]
header_message = \"Examples (WebGPU)\" header_message = \"Examples (WebGPU)\"
+++" +++"
.as_bytes(), .as_bytes(),
) )
.unwrap(); .unwrap();
} else {
index
.write_all(
"+++
title = \"Bevy Examples in WebGL2\"
template = \"examples.html\"
sort_by = \"weight\"
[extra]
header_message = \"Examples (WebGL2)\"
+++"
.as_bytes(),
)
.unwrap();
}
let mut categories = HashMap::new(); let mut categories = HashMap::new();
for to_show in examples_to_run { for to_show in examples_to_run {
@ -217,43 +287,61 @@ weight = {}
format!( format!(
"+++ "+++
title = \"{}\" title = \"{}\"
template = \"example-webgpu.html\" template = \"example{}.html\"
weight = {} weight = {}
description = \"{}\" description = \"{}\"
[extra] [extra]
technical_name = \"{}\" technical_name = \"{}\"
link = \"{}/{}\" link = \"/examples{}/{}/{}\"
image = \"../static/screenshots/{}/{}.png\" image = \"../static/screenshots/{}/{}.png\"
code_path = \"content/examples-webgpu/{}\" code_path = \"content/examples{}/{}\"
github_code_path = \"{}\" github_code_path = \"{}\"
header_message = \"Examples (WebGPU)\" header_message = \"Examples ({})\"
+++", +++",
to_show.name, to_show.name,
match api {
WebApi::Webgpu => "-webgpu",
WebApi::Webgl2 => "",
},
categories.get(&to_show.category).unwrap(), categories.get(&to_show.category).unwrap(),
to_show.description.replace('"', "'"), to_show.description.replace('"', "'"),
&to_show.technical_name.replace('_', "-"), &to_show.technical_name.replace('_', "-"),
match api {
WebApi::Webgpu => "-webgpu",
WebApi::Webgl2 => "",
},
&to_show.category, &to_show.category,
&to_show.technical_name.replace('_', "-"), &to_show.technical_name.replace('_', "-"),
&to_show.category, &to_show.category,
&to_show.technical_name, &to_show.technical_name,
match api {
WebApi::Webgpu => "-webgpu",
WebApi::Webgl2 => "",
},
code_path code_path
.components() .components()
.skip(1) .skip(1)
.collect::<PathBuf>() .collect::<PathBuf>()
.display(), .display(),
&to_show.path, &to_show.path,
match api {
WebApi::Webgpu => "WebGPU",
WebApi::Webgl2 => "WebGL2",
},
) )
.as_bytes(), .as_bytes(),
) )
.unwrap(); .unwrap();
} }
} }
Action::BuildWebGPUExamples { Action::BuildWasmExamples {
content_folder, content_folder,
website_hacks, website_hacks,
optimize_size, optimize_size,
api,
} => { } => {
let api = format!("{}", api);
let examples_to_build = parse_examples(); let examples_to_build = parse_examples();
let root_path = Path::new(&content_folder); let root_path = Path::new(&content_folder);
@ -282,30 +370,29 @@ header_message = \"Examples (WebGPU)\"
cmd!(sh, "sed -i.bak 's/asset_folder: \"assets\"/asset_folder: \"\\/assets\\/examples\\/\"/' crates/bevy_asset/src/lib.rs").run().unwrap(); cmd!(sh, "sed -i.bak 's/asset_folder: \"assets\"/asset_folder: \"\\/assets\\/examples\\/\"/' crates/bevy_asset/src/lib.rs").run().unwrap();
} }
let mut pb = ProgressBar::new( let work_to_do = || {
examples_to_build examples_to_build
.iter() .iter()
.filter(|to_build| to_build.wasm) .filter(|to_build| to_build.wasm)
.count() as u64, .skip(cli.page.unwrap_or(0) * cli.per_page.unwrap_or(0))
); .take(cli.per_page.unwrap_or(usize::MAX))
for to_build in examples_to_build { };
if !to_build.wasm {
continue;
}
let mut pb = ProgressBar::new(work_to_do().count() as u64);
for to_build in work_to_do() {
let sh = Shell::new().unwrap(); let sh = Shell::new().unwrap();
let example = &to_build.technical_name; let example = &to_build.technical_name;
if optimize_size { if optimize_size {
cmd!( cmd!(
sh, sh,
"cargo run -p build-wasm-example -- --api webgpu {example} --optimize-size" "cargo run -p build-wasm-example -- --api {api} {example} --optimize-size"
) )
.run() .run()
.unwrap(); .unwrap();
} else { } else {
cmd!( cmd!(
sh, sh,
"cargo run -p build-wasm-example -- --api webgpu {example}" "cargo run -p build-wasm-example -- --api {api} {example}"
) )
.run() .run()
.unwrap(); .unwrap();