diff --git a/examples/workplace/Cargo.lock b/examples/workplace/Cargo.lock new file mode 100644 index 00000000..4b3ecb99 --- /dev/null +++ b/examples/workplace/Cargo.lock @@ -0,0 +1,149 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "not-default-example" +version = "0.1.0" +dependencies = [ + "web-sys", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "proc-macro2" +version = "1.0.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "simple-example" +version = "0.1.0" +dependencies = [ + "web-sys", +] + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] diff --git a/examples/workplace/Cargo.toml b/examples/workplace/Cargo.toml new file mode 100644 index 00000000..5d72d8b4 --- /dev/null +++ b/examples/workplace/Cargo.toml @@ -0,0 +1,10 @@ +[workspace] +resolver = "2" +members = ["simple-example", "not-default-example"] +default-members = ["simple-example"] + +[workspace.package] +edition = "2021" +license = "MIT OR Apache-2.0" +rust-version = "1.76" +version = "0.27.2" diff --git a/examples/workplace/not-default-example/Cargo.toml b/examples/workplace/not-default-example/Cargo.toml new file mode 100644 index 00000000..9f759699 --- /dev/null +++ b/examples/workplace/not-default-example/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "not-default-example" +version = "0.1.0" +authors = ["Jens Reimann "] +edition = "2021" + +[dependencies] +web-sys = { version = "0.3", features = [ + "console", + "Document", + "HtmlElement", + "Node", + "Text", + "Window", +] } diff --git a/examples/workplace/not-default-example/index.html b/examples/workplace/not-default-example/index.html new file mode 100644 index 00000000..b167c487 --- /dev/null +++ b/examples/workplace/not-default-example/index.html @@ -0,0 +1,13 @@ + + + + + + Trunk | No-Rust + + + + +

Trunk without WASM in workspace (not default target)

+ + diff --git a/examples/workplace/not-default-example/src/main.rs b/examples/workplace/not-default-example/src/main.rs new file mode 100644 index 00000000..014f8deb --- /dev/null +++ b/examples/workplace/not-default-example/src/main.rs @@ -0,0 +1,15 @@ +use web_sys::window; + +fn start_app() { + let document = window() + .and_then(|win| win.document()) + .expect("Could not access document"); + let body = document.body().expect("Could not access document.body"); + let text_node = document.create_text_node("Hello, world from Vanilla Rust!"); + body.append_child(text_node.as_ref()) + .expect("Failed to append text"); +} + +fn main() { + start_app(); +} diff --git a/examples/workplace/simple-example/Cargo.toml b/examples/workplace/simple-example/Cargo.toml new file mode 100644 index 00000000..e7ffd81b --- /dev/null +++ b/examples/workplace/simple-example/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "simple-example" +version = "0.1.0" +authors = ["Jens Reimann "] +edition = "2021" + +[dependencies] +web-sys = { version = "0.3", features = [ + "console", + "Document", + "HtmlElement", + "Node", + "Text", + "Window", +] } diff --git a/examples/workplace/simple-example/index.html b/examples/workplace/simple-example/index.html new file mode 100644 index 00000000..67840ab2 --- /dev/null +++ b/examples/workplace/simple-example/index.html @@ -0,0 +1,13 @@ + + + + + + Trunk | No-Rust + + + + +

Trunk without WASM in workspace

+ + diff --git a/examples/workplace/simple-example/src/main.rs b/examples/workplace/simple-example/src/main.rs new file mode 100644 index 00000000..014f8deb --- /dev/null +++ b/examples/workplace/simple-example/src/main.rs @@ -0,0 +1,15 @@ +use web_sys::window; + +fn start_app() { + let document = window() + .and_then(|win| win.document()) + .expect("Could not access document"); + let body = document.body().expect("Could not access document.body"); + let text_node = document.create_text_node("Hello, world from Vanilla Rust!"); + body.append_child(text_node.as_ref()) + .expect("Failed to append text"); +} + +fn main() { + start_app(); +} diff --git a/src/config/models/mod.rs b/src/config/models/mod.rs index 94d6eff9..bbc925db 100644 --- a/src/config/models/mod.rs +++ b/src/config/models/mod.rs @@ -29,8 +29,8 @@ mod test; use anyhow::{bail, Context, Result}; use schemars::JsonSchema; use serde::Deserialize; -use source::Source; -use std::path::PathBuf; +use source::{workspace::WorkspaceConfig, Source}; +use std::path::{Path, PathBuf}; use tracing::log; /// Common configuration model functionality @@ -114,6 +114,59 @@ impl ConfigModel for Configuration { } } +pub async fn load_workspace_config( + current_path: &Path, + workspace_name: Option, +) -> Result> { + let cargo_toml = current_path.join("Cargo.toml"); + if cargo_toml.exists() { + if let Ok(workspace) = WorkspaceConfig::new(&cargo_toml).await { + match workspace_name { + Some(name) => { + if let Some(workspace) = workspace.get_workspace_by_name(&name) { + // get the parent directory of the workspace + let workspace = match workspace.parent() { + Some(parent) => parent, + None => { + return Err(anyhow::format_err!( + "unable to get parent directory of workspace '{}'", + workspace.display() + )); + } + }; + return Ok(Some(workspace.to_path_buf())); + } + return Err(anyhow::format_err!( + "workspace '{}' not found in {}", + name, + cargo_toml.display() + )); + } + None => { + if let Some(workspace) = workspace.get_default_workspace() { + // get the parent directory of the workspace + let workspace = match workspace.parent() { + Some(parent) => parent, + None => { + return Err(anyhow::format_err!( + "unable to get parent directory of workspace '{}'", + workspace.display() + )); + } + }; + return Ok(Some(workspace.to_path_buf())); + } + return Err(anyhow::format_err!( + "default workspace not found in {}", + cargo_toml.display() + )); + } + } + } + } + Ok(None) +} + /// Locate and load the configuration, given an optional file or directory. Falling back to the /// current directory. pub async fn load(path: Option) -> Result<(Configuration, PathBuf)> { diff --git a/src/config/models/source/mod.rs b/src/config/models/source/mod.rs index ecd6e1ec..5b3c84da 100644 --- a/src/config/models/source/mod.rs +++ b/src/config/models/source/mod.rs @@ -1,4 +1,5 @@ mod cargo; +pub mod workspace; use crate::config::{models::ConfigModel, Configuration}; use anyhow::bail; diff --git a/src/config/models/source/workspace.rs b/src/config/models/source/workspace.rs new file mode 100644 index 00000000..479a4eac --- /dev/null +++ b/src/config/models/source/workspace.rs @@ -0,0 +1,54 @@ +use anyhow::{Context, Result}; +use cargo_metadata::{Metadata, MetadataCommand}; +use serde::{Deserialize, Serialize}; +use std::path::Path; +use std::path::PathBuf; +use tokio::task::spawn_blocking; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WorkspaceConfig { + pub metadata: Metadata, +} + +impl WorkspaceConfig { + pub async fn new(manifest: &Path) -> Result { + let mut cmd = MetadataCommand::new(); + cmd.manifest_path(dunce::simplified(manifest)); + let metadata = spawn_blocking(move || cmd.exec()) + .await + .context("error awaiting spawned cargo metadata task")? + .context("error getting cargo metadata")?; + Ok(Self { metadata }) + } + + pub fn get_default_workspace(self) -> Option { + if let Some(default_member) = self.metadata.workspace_default_members.first() { + if let Some(found) = self + .metadata + .packages + .into_iter() + .find(|p| p.id == *default_member) + { + return Some(found.manifest_path.clone().into()); + } + } + None + } + + pub fn get_workspace_by_name(self, name: &str) -> Option { + // we search for the package in the workspace packages list + if let Some(one_package) = self.metadata.packages.iter().find(|m| m.name == name) { + // we check if the package is present in the workspace members list + if self + .metadata + .workspace_members + .into_iter() + .any(|p| p == one_package.id) + { + // we return the manifest path of the package + return Some(one_package.manifest_path.clone().into()); + } + } + None + } +} diff --git a/src/main.rs b/src/main.rs index 9a179396..3fd4fca8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ mod ws; use anyhow::{Context, Result}; use clap::{ArgAction, Parser, Subcommand, ValueEnum}; use common::STARTING; +use config::models::load_workspace_config; use std::io::IsTerminal; use std::path::PathBuf; use std::process::ExitCode; @@ -144,6 +145,9 @@ struct Trunk { /// Support for `NO_COLOR` environment variable #[arg(long, env = "NO_COLOR", global(true))] pub no_color: bool, + + #[arg(long = "workspace", env = "TRUNK_CRATE_WORKSPACE")] + pub crate_workspace: Option, } impl Trunk { @@ -174,13 +178,31 @@ impl Trunk { pub async fn run(self) -> Result<()> { version::update_check(self.skip_version_check | self.offline.unwrap_or_default()); + let config_path = match self.config { + Some(path) => Some(path), + None => { + let cwd = std::env::current_dir().context("unable to get current directory")?; + let workspace_config = load_workspace_config(&cwd, self.crate_workspace).await?; + + if let Some(config_path_from_workspace) = workspace_config { + tracing::info!( + "Workspace: loading config from {}", + config_path_from_workspace.display() + ); + Some(config_path_from_workspace) + } else { + self.config + } + } + }; + match self.action { - TrunkSubcommands::Build(inner) => inner.run(self.config).await, - TrunkSubcommands::Clean(inner) => inner.run(self.config).await, - TrunkSubcommands::Serve(inner) => inner.run(self.config).await, - TrunkSubcommands::Watch(inner) => inner.run(self.config).await, - TrunkSubcommands::Config(inner) => inner.run(self.config).await, - TrunkSubcommands::Tools(inner) => inner.run(self.config).await, + TrunkSubcommands::Build(inner) => inner.run(config_path).await, + TrunkSubcommands::Clean(inner) => inner.run(config_path).await, + TrunkSubcommands::Serve(inner) => inner.run(config_path).await, + TrunkSubcommands::Watch(inner) => inner.run(config_path).await, + TrunkSubcommands::Config(inner) => inner.run(config_path).await, + TrunkSubcommands::Tools(inner) => inner.run(config_path).await, } } }