Skip to content

Commit 044f3cb

Browse files
alexcrichtonPauan
authored andcommitted
Don't run Cargo in a build script
Instead refactor things so webidl-tests can use the Rust-code-generation as a library in a build script. Also fixes `cargo fmt` in the repository.
1 parent 712ef70 commit 044f3cb

File tree

7 files changed

+147
-139
lines changed

7 files changed

+147
-139
lines changed

crates/web-sys/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#![doc(html_root_url = "https://docs.rs/web-sys/0.2")]
1515
#![allow(deprecated)]
1616

17+
#[allow(unused_imports, non_snake_case)]
1718
mod features;
1819
pub use features::*;
1920

crates/webidl-tests/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ name = "webidl-tests"
33
version = "0.1.0"
44
authors = ["The wasm-bindgen Developers"]
55
edition = "2018"
6+
publish = false
67

78
[lib]
89
test = false
@@ -13,6 +14,9 @@ path = 'lib.rs'
1314
js-sys = { path = '../js-sys' }
1415
wasm-bindgen = { path = '../..' }
1516

17+
[build-dependencies]
18+
wasm-bindgen-webidl = { path = "../webidl" }
19+
1620
[dev-dependencies]
1721
wasm-bindgen-test = { path = '../test' }
1822

crates/webidl-tests/build.rs

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,7 @@
1-
use std::io::Result;
2-
use std::process::Command;
1+
use std::env;
2+
use std::path::PathBuf;
33

4-
fn main() -> Result<()> {
5-
let result = Command::new("cargo")
6-
.arg("run")
7-
.arg("--release")
8-
.arg("--package")
9-
.arg("wasm-bindgen-webidl")
10-
.arg("webidls")
11-
.arg("generated")
12-
.arg("--no-features")
13-
.status()?;
14-
15-
assert!(result.success());
16-
17-
Ok(())
4+
fn main() {
5+
let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
6+
wasm_bindgen_webidl::generate("webidls".as_ref(), &out_dir, false).unwrap();
187
}

crates/webidl-tests/main.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ fn keep() {
1515
noop();
1616
}
1717

18-
mod generated;
18+
#[allow(unused_imports, non_snake_case)]
19+
mod generated {
20+
include!(concat!(env!("OUT_DIR"), "/mod.rs"));
21+
}
1922

2023
pub mod array;
2124
pub mod array_buffer;

crates/webidl/src/generator.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,11 @@ fn maybe_unstable_docs(unstable: bool) -> Option<proc_macro2::TokenStream> {
6161
}
6262

6363
fn generate_arguments(arguments: &[(Ident, Type)], variadic: bool) -> Vec<TokenStream> {
64-
let last = arguments.len() - 1;
65-
6664
arguments
6765
.into_iter()
6866
.enumerate()
6967
.map(|(i, (name, ty))| {
70-
if variadic && i == last {
68+
if variadic && i + 1 == arguments.len() {
7169
quote!( #name: &::js_sys::Array )
7270
} else {
7371
quote!( #name: #ty )

crates/webidl/src/lib.rs

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,17 @@ use crate::util::{
2828
camel_case_ident, is_structural, shouty_snake_case_ident, snake_case_ident, throws,
2929
webidl_const_v_to_backend_const_v, TypePosition,
3030
};
31+
use anyhow::Context;
3132
use anyhow::Result;
3233
use proc_macro2::{Ident, TokenStream};
3334
use quote::ToTokens;
35+
use sourcefile::SourceFile;
3436
use std::collections::{BTreeMap, BTreeSet};
37+
use std::ffi::OsStr;
3538
use std::fmt;
39+
use std::fs;
40+
use std::path::{Path, PathBuf};
41+
use std::process::Command;
3642
use wasm_bindgen_backend::util::rust_ident;
3743
use weedle::attribute::ExtendedAttributeList;
3844
use weedle::dictionary::DictionaryMember;
@@ -678,3 +684,127 @@ impl<'src> FirstPassRecord<'src> {
678684
.to_tokens(&mut program.tokens);
679685
}
680686
}
687+
688+
/// Generates Rust source code with #[wasm_bindgen] annotations.
689+
///
690+
/// * Reads WebIDL files in `from`
691+
/// * Generates Rust source code in the directory `to`
692+
/// * `generate_features` indicates whether everything is gated by features or
693+
/// not
694+
///
695+
/// If features are enabled, returns a string that should be appended to
696+
/// `Cargo.toml` which lists all the known features.
697+
pub fn generate(from: &Path, to: &Path, generate_features: bool) -> Result<String> {
698+
let source = read_source_from_path(&from.join("enabled"))?;
699+
let unstable_source = read_source_from_path(&from.join("unstable"))?;
700+
701+
let features = parse_webidl(generate_features, source, unstable_source)?;
702+
703+
if to.exists() {
704+
fs::remove_dir_all(&to).context("Removing features directory")?;
705+
}
706+
707+
fs::create_dir_all(&to).context("Creating features directory")?;
708+
709+
for (name, feature) in features.iter() {
710+
let out_file_path = to.join(format!("gen_{}.rs", name));
711+
712+
fs::write(&out_file_path, &feature.code)?;
713+
714+
rustfmt(&out_file_path, name)?;
715+
}
716+
717+
let binding_file = features.keys().map(|name| {
718+
if generate_features {
719+
format!("#[cfg(feature = \"{name}\")] mod gen_{name};\n#[cfg(feature = \"{name}\")] pub use gen_{name}::*;", name = name)
720+
} else {
721+
format!("mod gen_{name};\npub use gen_{name}::*;", name = name)
722+
}
723+
}).collect::<Vec<_>>().join("\n\n");
724+
725+
fs::write(to.join("mod.rs"), binding_file)?;
726+
727+
rustfmt(&to.join("mod.rs"), "mod")?;
728+
729+
return if generate_features {
730+
let features = features
731+
.iter()
732+
.map(|(name, feature)| {
733+
let features = feature
734+
.required_features
735+
.iter()
736+
.map(|x| format!("\"{}\"", x))
737+
.collect::<Vec<_>>()
738+
.join(", ");
739+
format!("{} = [{}]", name, features)
740+
})
741+
.collect::<Vec<_>>()
742+
.join("\n");
743+
Ok(features)
744+
} else {
745+
Ok(String::new())
746+
};
747+
748+
/// Read all WebIDL files in a directory into a single `SourceFile`
749+
fn read_source_from_path(dir: &Path) -> Result<SourceFile> {
750+
let entries = fs::read_dir(dir).context("reading webidls directory")?;
751+
let mut source = SourceFile::default();
752+
for entry in entries {
753+
let entry = entry.context(format!("getting {}/*.webidl entry", dir.display()))?;
754+
let path = entry.path();
755+
if path.extension() != Some(OsStr::new("webidl")) {
756+
continue;
757+
}
758+
source = source
759+
.add_file(&path)
760+
.with_context(|| format!("reading contents of file \"{}\"", path.display()))?;
761+
}
762+
763+
Ok(source)
764+
}
765+
766+
fn rustfmt(path: &PathBuf, name: &str) -> Result<()> {
767+
// run rustfmt on the generated file - really handy for debugging
768+
let result = Command::new("rustfmt")
769+
.arg("--edition")
770+
.arg("2018")
771+
.arg(&path)
772+
.status()
773+
.context(format!("rustfmt on file {}", name))?;
774+
775+
assert!(result.success(), "rustfmt on file {}", name);
776+
777+
Ok(())
778+
}
779+
780+
fn parse_webidl(
781+
generate_features: bool,
782+
enabled: SourceFile,
783+
unstable: SourceFile,
784+
) -> Result<BTreeMap<String, Feature>> {
785+
let options = Options {
786+
features: generate_features,
787+
};
788+
789+
match compile(&enabled.contents, &unstable.contents, options) {
790+
Ok(features) => Ok(features),
791+
Err(e) => {
792+
if let Some(err) = e.downcast_ref::<WebIDLParseError>() {
793+
if let Some(pos) = enabled.resolve_offset(err.0) {
794+
let ctx = format!(
795+
"compiling WebIDL into wasm-bindgen bindings in file \
796+
\"{}\", line {} column {}",
797+
pos.filename,
798+
pos.line + 1,
799+
pos.col + 1
800+
);
801+
return Err(e.context(ctx));
802+
} else {
803+
return Err(e.context("compiling WebIDL into wasm-bindgen bindings"));
804+
}
805+
}
806+
return Err(e.context("compiling WebIDL into wasm-bindgen bindings"));
807+
}
808+
}
809+
}
810+
}

crates/webidl/src/main.rs

Lines changed: 2 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -24,131 +24,14 @@ struct Opt {
2424
no_features: bool,
2525
}
2626

27-
/// Read all WebIDL files in a directory into a single `SourceFile`
28-
fn read_source_from_path(dir: &Path) -> Result<SourceFile> {
29-
let entries = fs::read_dir(dir).context("reading webidls directory")?;
30-
let mut source = SourceFile::default();
31-
for entry in entries {
32-
let entry = entry.context(format!("getting {}/*.webidl entry", dir.display()))?;
33-
let path = entry.path();
34-
if path.extension() != Some(OsStr::new("webidl")) {
35-
continue;
36-
}
37-
source = source
38-
.add_file(&path)
39-
.with_context(|| format!("reading contents of file \"{}\"", path.display()))?;
40-
}
41-
42-
Ok(source)
43-
}
44-
45-
fn rustfmt(path: &PathBuf, name: &str) -> Result<()> {
46-
// run rustfmt on the generated file - really handy for debugging
47-
let result = Command::new("rustfmt")
48-
.arg("--edition")
49-
.arg("2018")
50-
.arg(&path)
51-
.status()
52-
.context(format!("rustfmt on file {}", name))?;
53-
54-
assert!(result.success(), "rustfmt on file {}", name);
55-
56-
Ok(())
57-
}
58-
59-
fn parse_webidl(
60-
opt: &Opt,
61-
enabled: SourceFile,
62-
unstable: SourceFile,
63-
) -> Result<BTreeMap<String, Feature>> {
64-
let options = wasm_bindgen_webidl::Options {
65-
features: !opt.no_features,
66-
};
67-
68-
match wasm_bindgen_webidl::compile(&enabled.contents, &unstable.contents, options) {
69-
Ok(features) => Ok(features),
70-
Err(e) => {
71-
if let Some(err) = e.downcast_ref::<wasm_bindgen_webidl::WebIDLParseError>() {
72-
if let Some(pos) = enabled.resolve_offset(err.0) {
73-
let ctx = format!(
74-
"compiling WebIDL into wasm-bindgen bindings in file \
75-
\"{}\", line {} column {}",
76-
pos.filename,
77-
pos.line + 1,
78-
pos.col + 1
79-
);
80-
return Err(e.context(ctx));
81-
} else {
82-
return Err(e.context("compiling WebIDL into wasm-bindgen bindings"));
83-
}
84-
}
85-
return Err(e.context("compiling WebIDL into wasm-bindgen bindings"));
86-
}
87-
}
88-
}
89-
9027
fn main() -> Result<()> {
9128
env_logger::init();
9229

9330
let opt = Opt::from_args();
94-
95-
let from = &opt.input_dir;
96-
let to = &opt.output_dir;
97-
98-
let source = read_source_from_path(&from.join("enabled"))?;
99-
let unstable_source = read_source_from_path(&from.join("unstable"))?;
100-
101-
let features = parse_webidl(&opt, source, unstable_source)?;
102-
103-
if to.exists() {
104-
fs::remove_dir_all(&to).context("Removing features directory")?;
105-
}
106-
107-
fs::create_dir_all(&to).context("Creating features directory")?;
108-
109-
for (name, feature) in features.iter() {
110-
let out_file_path = to.join(format!("gen_{}.rs", name));
111-
112-
fs::write(&out_file_path, &feature.code)?;
113-
114-
rustfmt(&out_file_path, name)?;
115-
}
116-
117-
let binding_file = features.keys().map(|name| {
118-
if opt.no_features {
119-
format!("mod gen_{name};\npub use gen_{name}::*;", name = name)
120-
} else {
121-
format!("#[cfg(feature = \"{name}\")] mod gen_{name};\n#[cfg(feature = \"{name}\")] pub use gen_{name}::*;", name = name)
122-
}
123-
}).collect::<Vec<_>>().join("\n\n");
124-
125-
fs::write(
126-
to.join("mod.rs"),
127-
format!(
128-
"#![allow(non_snake_case, unused_imports)]\n\n{}",
129-
binding_file
130-
),
131-
)?;
132-
133-
rustfmt(&to.join("mod.rs"), "mod")?;
134-
31+
let features =
32+
wasm_bindgen_webidl::generate(&opt.input_dir, &opt.output_dir, !opt.no_features)?;
13533
if !opt.no_features {
136-
let features = features
137-
.iter()
138-
.map(|(name, feature)| {
139-
let features = feature
140-
.required_features
141-
.iter()
142-
.map(|x| format!("\"{}\"", x))
143-
.collect::<Vec<_>>()
144-
.join(", ");
145-
format!("{} = [{}]", name, features)
146-
})
147-
.collect::<Vec<_>>()
148-
.join("\n");
149-
15034
fs::write(&"features", features).context("writing features to current directory")?;
15135
}
152-
15336
Ok(())
15437
}

0 commit comments

Comments
 (0)