Skip to content

Commit 1c8e363

Browse files
authored
Merge pull request #27 from thedodd/23-workspaces-and-multi-project
Handle multi-project & workspace contexts.
2 parents f80567a + 58bbbbc commit 1c8e363

File tree

8 files changed

+93
-46
lines changed

8 files changed

+93
-46
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ changelog
33

44
## Unreleased
55

6+
## 0.3.0
7+
### added
8+
- Handle multi-project & workspace contexts. Thank you @oli-obk for developing [cargo_metadata](https://github.com/oli-obk/cargo_metadata).
9+
610
## 0.2.0
711
### changed
812
- All CLI output has been improved using console & indicatif. Builds, asset pipelines, and the like are using a progress spinner along with messages. All in all this provides a much more clean CLI output experience.

Cargo.lock

Lines changed: 23 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "trunk"
3-
version = "0.2.0"
3+
version = "0.3.0"
44
edition = "2018"
55
description = "Build, bundle & ship your Rust WASM application to the web."
66
license = "MIT/Apache-2.0"
@@ -14,6 +14,7 @@ keywords = ["wasm", "bundler", "web", "build-tool", "compiler"]
1414
anyhow = "1.0.32"
1515
async-process = "0.1.1"
1616
async-std = { version="1.6.3", features=["attributes", "unstable"] }
17+
cargo_metadata = "0.11.1"
1718
console = "0.12.0"
1819
futures = "0.3.5"
1920
indicatif = "0.15.0"

src/build.rs

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ use anyhow::{anyhow, bail, ensure, Result};
88
use async_process::{Command, Stdio};
99
use async_std::fs;
1010
use async_std::task::{spawn, spawn_blocking, JoinHandle};
11+
use cargo_metadata::{MetadataCommand, Metadata, Package};
1112
use console::Emoji;
1213
use futures::stream::{FuturesUnordered, StreamExt};
1314
use indicatif::ProgressBar;
1415
use nipper::Document;
15-
use serde::{Serialize, Deserialize};
16-
17-
use crate::common::get_cwd;
1816

1917
const TRUNK_ID: &str = "__trunk-id";
2018
const HREF_ATTR: &str = "href";
@@ -27,7 +25,7 @@ const HREF_ATTR: &str = "href";
2725
/// build routines can be cleanly abstracted away form any specific CLI endpoints.
2826
pub struct BuildSystem {
2927
/// The `Cargo.toml` manifest of the app being built.
30-
manifest: CargoManifest,
28+
manifest: CargoMetadata,
3129
/// The path to the source HTML document from which the output `index.html` will be built.
3230
target_html_path: Arc<PathBuf>,
3331
/// The parent directory of `target_html_path`.
@@ -56,16 +54,13 @@ impl BuildSystem {
5654
///
5755
/// Reducing the number of assumptions here should help us to stay flexible when adding new
5856
/// commands, rafctoring and the like.
59-
pub async fn new(manifest: CargoManifest, target_html_path: PathBuf, release: bool, dist: PathBuf, public_url: String) -> Result<Self> {
57+
pub async fn new(manifest: CargoMetadata, target_html_path: PathBuf, release: bool, dist: PathBuf, public_url: String) -> Result<Self> {
6058
let mode_segment = if release { "release" } else { "debug" };
61-
let cwd = std::env::current_dir().map_err(|_| anyhow!("failed to determine current working directory"))?;
62-
let app_target_wasm = cwd
63-
.join("target")
59+
let app_target_wasm = manifest.metadata.target_directory
6460
.join("wasm32-unknown-unknown")
6561
.join(mode_segment)
6662
.join(format!("{}.wasm", &manifest.package.name));
67-
let bindgen_out = cwd
68-
.join("target")
63+
let bindgen_out = manifest.metadata.target_directory
6964
.join("wasm-bindgen")
7065
.join(mode_segment);
7166
let target_html_path = target_html_path.canonicalize()
@@ -452,34 +447,43 @@ struct WasmBindgenOutput {
452447
//////////////////////////////////////////////////////////////////////////////
453448
//////////////////////////////////////////////////////////////////////////////
454449

455-
/// A model of the Cargo.toml `package` section.
456-
#[derive(Serialize, Deserialize)]
457-
pub struct CargoPackage {
458-
/// The name of the crate.
450+
/// A wrapper around the cargo project's metadata.
451+
pub struct CargoMetadata {
452+
/// The metadata parsed from the cargo project.
453+
pub metadata: Metadata,
454+
/// The metadata package info on this package.
455+
pub package: Package,
456+
/// The name of the cargo project's build output file.
459457
pub name: String,
460-
/// The version of the crate.
461-
pub version: String,
462-
}
463-
464-
/// A model of the parts of a `Cargo.toml` file which we actually care about.
465-
#[derive(Serialize, Deserialize)]
466-
pub struct CargoManifest {
467-
/// The package section of `Cargo.toml`.
468-
pub package: CargoPackage,
469458
}
470459

471-
impl CargoManifest {
472-
/// Read the `Cargo.toml` manifest in the CWD.
473-
pub async fn read_cwd_manifest() -> Result<Self> {
474-
let manifest_path = get_cwd().await?.join("Cargo.toml");
475-
let manifest_raw = fs::read_to_string(&manifest_path).await
476-
.map_err(|err| anyhow!("error reading Cargo.toml file: {}", err))?;
477-
let mut manifest: Self = toml::from_str(&manifest_raw)
478-
.map_err(|err| anyhow!("error parsing Cargo.toml: {}", err))?;
479-
480-
// Update the package name to match what its output name will be.
481-
manifest.package.name = manifest.package.name.replace("-", "_");
460+
impl CargoMetadata {
461+
/// Get the project's cargo metadata of the CWD, or of the project specified by the given manifest path.
462+
pub async fn new(manifest: &Option<PathBuf>) -> Result<Self> {
463+
// Fetch the cargo project's metadata.
464+
let mut cmd = MetadataCommand::new();
465+
if let Some(manifest) = manifest.as_ref() {
466+
cmd.manifest_path(manifest);
467+
}
468+
let metadata = spawn_blocking(move || {
469+
cmd.exec()
470+
}).await?;
471+
472+
// Get a handle to this project's package info.
473+
let resolve = match metadata.resolve.as_ref() {
474+
Some(resolve) => resolve,
475+
None => bail!("missing package info from cargo project metadata"),
476+
};
477+
let pkgid = match resolve.root.as_ref() {
478+
Some(pkgid) => pkgid,
479+
None => bail!("package id missing while processing cargo metadata"),
480+
};
481+
let package = match metadata.packages.iter().find(|pkg| &pkg.id == pkgid) {
482+
Some(package) => package.clone(),
483+
None => bail!("error finding package info in cargo metadata"),
484+
};
485+
let name = package.name.replace("-", "_");
482486

483-
Ok(manifest)
487+
Ok(Self{metadata, package, name})
484488
}
485489
}

src/cmd/build.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::path::PathBuf;
33
use anyhow::Result;
44
use structopt::StructOpt;
55

6-
use crate::build::{BuildSystem, CargoManifest};
6+
use crate::build::{BuildSystem, CargoMetadata};
77
use crate::common::parse_public_url;
88

99
/// Build the Rust WASM app and all of its assets.
@@ -23,11 +23,14 @@ pub struct Build {
2323
/// The public URL from which assets are to be served.
2424
#[structopt(long, default_value="/", parse(from_str=parse_public_url))]
2525
public_url: String,
26+
/// Path to Cargo.toml.
27+
#[structopt(long="manifest-path", parse(from_os_str))]
28+
manifest: Option<PathBuf>,
2629
}
2730

2831
impl Build {
2932
pub async fn run(self) -> Result<()> {
30-
let manifest = CargoManifest::read_cwd_manifest().await?;
33+
let manifest = CargoMetadata::new(&self.manifest).await?;
3134
let mut system = BuildSystem::new(
3235
manifest, self.target.clone(), self.release,
3336
self.dist.clone(), self.public_url.clone(),

src/cmd/serve.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub struct Serve {
2222
target: PathBuf,
2323

2424
/// The port to serve on.
25-
#[structopt(short, long, default_value="8080")]
25+
#[structopt(long, default_value="8080")]
2626
port: u16,
2727
/// Build in release mode.
2828
#[structopt(long)]
@@ -39,14 +39,18 @@ pub struct Serve {
3939
/// Open a browser tab once the initial build is complete.
4040
#[structopt(long)]
4141
open: bool,
42+
/// Path to Cargo.toml.
43+
#[structopt(long="manifest-path", parse(from_os_str))]
44+
manifest: Option<PathBuf>,
4245
}
4346

4447
impl Serve {
4548
pub async fn run(self) -> Result<()> {
4649
let (target, release, dist, public_url, ignore) = (
47-
self.target.clone(), self.release, self.dist.clone(), self.public_url.clone(), self.ignore.clone().unwrap_or_default(),
50+
self.target.clone(), self.release, self.dist.clone(),
51+
self.public_url.clone(), self.ignore.clone().unwrap_or_default(),
4852
);
49-
let mut watcher = WatchSystem::new(target, release, dist, public_url, ignore).await?;
53+
let mut watcher = WatchSystem::new(target, release, dist, public_url, ignore, self.manifest.clone()).await?;
5054
watcher.build().await;
5155
let progress = watcher.get_progress_handle();
5256

src/cmd/watch.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,17 @@ pub struct Watch {
2626
/// Additional paths to ignore.
2727
#[structopt(short, long, parse(from_os_str))]
2828
ignore: Option<Vec<PathBuf>>,
29+
/// Path to Cargo.toml.
30+
#[structopt(long="manifest-path", parse(from_os_str))]
31+
manifest: Option<PathBuf>,
2932
}
3033

3134
impl Watch {
3235
pub async fn run(self) -> Result<()> {
33-
let mut system = WatchSystem::new(self.target, self.release, self.dist, self.public_url, self.ignore.unwrap_or_default()).await?;
36+
let mut system = WatchSystem::new(
37+
self.target, self.release, self.dist, self.public_url,
38+
self.ignore.unwrap_or_default(), self.manifest,
39+
).await?;
3440
system.build().await;
3541
system.run().await;
3642
Ok(())

src/watch.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use indicatif::ProgressBar;
1111
use notify::{Watcher, RecursiveMode, watcher};
1212

1313
use crate::common::get_cwd;
14-
use crate::build::{BuildSystem, CargoManifest};
14+
use crate::build::{BuildSystem, CargoMetadata};
1515

1616
/// A watch system wrapping a build system and a watcher.
1717
pub struct WatchSystem {
@@ -22,7 +22,10 @@ pub struct WatchSystem {
2222

2323
impl WatchSystem {
2424
/// Create a new instance.
25-
pub async fn new(target: PathBuf, release: bool, dist: PathBuf, public_url: String, ignore: Vec<PathBuf>) -> Result<Self> {
25+
pub async fn new(
26+
target: PathBuf, release: bool, dist: PathBuf, public_url: String,
27+
ignore: Vec<PathBuf>, manifest: Option<PathBuf>,
28+
) -> Result<Self> {
2629
// Process ignore list.
2730
let cwd = get_cwd().await?;
2831
let mut ignore = ignore.into_iter().try_fold(vec![], |mut acc, path| -> Result<Vec<PathBuf>> {
@@ -33,7 +36,7 @@ impl WatchSystem {
3336
ignore.append(&mut vec![cwd.join("target"), cwd.join(&dist)]);
3437

3538
// Perform an initial build.
36-
let manifest = CargoManifest::read_cwd_manifest().await?;
39+
let manifest = CargoMetadata::new(&manifest).await?;
3740
let build = BuildSystem::new(manifest, target, release, dist, public_url).await?;
3841
let progress = build.get_progress_handle();
3942

0 commit comments

Comments
 (0)