diff --git a/Cargo.lock b/Cargo.lock index 9334ca674..acefd5505 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,19 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom 0.2.12", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.2" @@ -246,6 +259,38 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cc" version = "1.0.83" @@ -255,6 +300,16 @@ dependencies = [ "libc", ] +[[package]] +name = "cfg-expr" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa50868b64a9a6fda9d593ce778849ea8715cd2a3d2cc17ffdb4a2f2f2f1961d" +dependencies = [ + "smallvec", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -397,10 +452,13 @@ dependencies = [ "anyhow", "clap", "console", + "guppy", "ignore", "libc", "ramhorns", + "rustdoc-types", "serde", + "serde_json", "similar", "tokio", "tokio-fd", @@ -570,6 +628,12 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "debug-ignore" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe7ed1d93f4553003e20b629abe9085e1e81b1429520f897f8f8860bc6dfc21" + [[package]] name = "derive_builder" version = "0.13.0" @@ -634,6 +698,12 @@ dependencies = [ "serde", ] +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + [[package]] name = "encode_unicode" version = "0.3.6" @@ -707,6 +777,12 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "fnv" version = "1.0.7" @@ -903,6 +979,39 @@ dependencies = [ "walkdir", ] +[[package]] +name = "guppy" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34e99a7734579b834a076ef11789783c153c6eb5fb3520ed15bc41f483f0f317" +dependencies = [ + "ahash", + "camino", + "cargo_metadata", + "cfg-if", + "debug-ignore", + "fixedbitset", + "guppy-workspace-hack", + "indexmap", + "itertools", + "nested", + "once_cell", + "pathdiff", + "petgraph", + "semver", + "serde", + "serde_json", + "smallvec", + "static_assertions", + "target-spec", +] + +[[package]] +name = "guppy-workspace-hack" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92620684d99f750bae383ecb3be3748142d6095760afd5cbcf2261e9a279d780" + [[package]] name = "hashbrown" version = "0.14.3" @@ -1067,6 +1176,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.10" @@ -1171,6 +1289,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "nested" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b420f638f07fe83056b55ea190bb815f609ec5a35e7017884a10f78839c9e" + [[package]] name = "num-traits" version = "0.2.17" @@ -1234,12 +1358,31 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +dependencies = [ + "camino", +] + [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap", +] + [[package]] name = "phf" version = "0.10.1" @@ -1563,6 +1706,15 @@ dependencies = [ "semver", ] +[[package]] +name = "rustdoc-types" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0904b9147011800e63763fb9e49bbeaf76c1b6ab8982824c659dce5433712559" +dependencies = [ + "serde", +] + [[package]] name = "rustix" version = "0.38.31" @@ -1602,6 +1754,9 @@ name = "semver" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +dependencies = [ + "serde", +] [[package]] name = "serde" @@ -1650,9 +1805,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -1777,6 +1932,24 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "target-lexicon" +version = "0.12.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" + +[[package]] +name = "target-spec" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36a8e795b1824524d13cdf04f73cf8b4f244ce86c96b4d2a83a6ca1a753d2752" +dependencies = [ + "cfg-expr", + "guppy-workspace-hack", + "target-lexicon", + "unicode-ident", +] + [[package]] name = "tempfile" version = "3.9.0" @@ -2263,3 +2436,23 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] diff --git a/crux_cli/Cargo.toml b/crux_cli/Cargo.toml index be9103ad1..9955b3a80 100644 --- a/crux_cli/Cargo.toml +++ b/crux_cli/Cargo.toml @@ -17,10 +17,13 @@ path = "src/main.rs" anyhow.workspace = true clap = { version = "4.3.24", features = ["derive"] } console = "0.15.8" +guppy = "0.17.5" ignore = "0.4.22" libc = "0.2.153" ramhorns = "0.14.0" +rustdoc-types = "0.24.0" serde = { workspace = true, features = ["derive"] } +serde_json = "1.0.114" similar = { version = "2.4.0", features = ["inline"] } tokio = { version = "1.36.0", features = ["full"] } tokio-fd = "0.3.0" diff --git a/crux_cli/src/args.rs b/crux_cli/src/args.rs index f94e283ad..70aabd562 100644 --- a/crux_cli/src/args.rs +++ b/crux_cli/src/args.rs @@ -48,9 +48,9 @@ pub(crate) struct DoctorArgs { #[derive(Args)] pub(crate) struct CodegenArgs { - /// path to the directory containing the Cargo.toml manifest + /// name of the library containing your Crux App #[arg(long, short)] - pub path: PathBuf, + pub lib: String, } #[cfg(test)] diff --git a/crux_cli/src/codegen.rs b/crux_cli/src/codegen.rs index efc89a60d..3b9316e13 100644 --- a/crux_cli/src/codegen.rs +++ b/crux_cli/src/codegen.rs @@ -1,10 +1,20 @@ -use anyhow::Result; -use std::io::{stdout, IsTerminal}; -use tokio::process::Command; +use anyhow::{bail, Result}; +use rustdoc_types::{Crate, Impl, ItemEnum, Path}; +use std::{ + fs::File, + io::{stdout, IsTerminal}, +}; +use tokio::{process::Command, task::spawn_blocking}; -use crate::{args::CodegenArgs, command_runner}; +use crate::{args::CodegenArgs, command_runner, graph}; pub async fn codegen(args: &CodegenArgs) -> Result<()> { + let graph = graph::compute_package_graph()?; + + let Ok(lib) = graph.workspace().member_by_path(&args.lib) else { + bail!("Could not find workspace package with path {}", args.lib) + }; + let mut cmd = Command::new("cargo"); cmd.env("RUSTC_BOOTSTRAP", "1") .env( @@ -12,8 +22,9 @@ pub async fn codegen(args: &CodegenArgs) -> Result<()> { "-Z unstable-options --output-format=json --cap-lints=allow", ) .arg("doc") + .arg("--no-deps") .arg("--manifest-path") - .arg(&args.path) + .arg(lib.manifest_path()) .arg("--lib"); if stdout().is_terminal() { cmd.arg("--color=always"); @@ -21,5 +32,37 @@ pub async fn codegen(args: &CodegenArgs) -> Result<()> { command_runner::run(&mut cmd).await?; + let target_directory = graph.workspace().target_directory().as_std_path(); + let json_path = target_directory + .join("doc") + .join(format!("{}.json", lib.name().replace("-", "_"))); + + let rustdoc: Crate = spawn_blocking(move || { + let file = File::open(&json_path)?; + let crate_: Crate = serde_json::from_reader(file)?; + Ok::(crate_) + }) + .await??; + + if let Some(name) = rustdoc.index.iter().find_map(|(_k, v)| { + if let ItemEnum::Impl(Impl { + trait_: Some(rustdoc_types::Path { + name: trait_name, .. + }), + for_: rustdoc_types::Type::ResolvedPath(Path { name, .. }), + .. + }) = &v.inner + { + (trait_name == &"App".to_string()).then(|| name) + } else { + None + } + }) { + println!( + "The struct that implements crux_core::App is called {:?}", + name + ); + } + Ok(()) } diff --git a/crux_cli/src/graph.rs b/crux_cli/src/graph.rs new file mode 100644 index 000000000..90cc84ec0 --- /dev/null +++ b/crux_cli/src/graph.rs @@ -0,0 +1,8 @@ +use anyhow::{anyhow, Result}; +use guppy::{graph::PackageGraph, MetadataCommand}; + +pub(crate) fn compute_package_graph() -> Result { + let mut cmd = MetadataCommand::new(); + let package_graph = PackageGraph::from_command(&mut cmd); + package_graph.map_err(|e| anyhow!(e)) +} diff --git a/crux_cli/src/main.rs b/crux_cli/src/main.rs index 2443c6ab0..453962559 100644 --- a/crux_cli/src/main.rs +++ b/crux_cli/src/main.rs @@ -10,6 +10,7 @@ mod command_runner; mod config; mod diff; mod doctor; +mod graph; mod template; mod workspace;