diff --git a/crates/wasm-pkg-core/src/manifest.rs b/crates/wasm-pkg-core/src/manifest.rs index 7e1924a..78dd347 100644 --- a/crates/wasm-pkg-core/src/manifest.rs +++ b/crates/wasm-pkg-core/src/manifest.rs @@ -13,7 +13,9 @@ pub mod workspace; use workspace::*; -use crate::manifest::paths::{find_root_iter, find_root_manifest_for_wd}; +use crate::manifest::paths::find_root_iter; + +pub use crate::manifest::paths::find_root_manifest_for_wd; /// The default name of the manifest file. pub const MANIFEST_FILE_NAME: &str = "wkg.toml"; diff --git a/crates/wasm-pkg-core/src/manifest/paths.rs b/crates/wasm-pkg-core/src/manifest/paths.rs index 6bcf8d0..e178833 100644 --- a/crates/wasm-pkg-core/src/manifest/paths.rs +++ b/crates/wasm-pkg-core/src/manifest/paths.rs @@ -4,7 +4,7 @@ use std::path::{Component, Path, PathBuf}; use crate::manifest::MANIFEST_FILE_NAME; /// Find the first ancestor [`super::Manifest`] path for current working directory. -pub(crate) fn find_root_manifest_for_wd(cwd: impl AsRef) -> Option { +pub fn find_root_manifest_for_wd(cwd: impl AsRef) -> Option { for current in cwd.as_ref().ancestors() { let manifest = current.join(MANIFEST_FILE_NAME); if manifest.exists() { diff --git a/crates/wkg/src/wit.rs b/crates/wkg/src/wit.rs index 38c7cdc..76cb811 100644 --- a/crates/wkg/src/wit.rs +++ b/crates/wkg/src/wit.rs @@ -11,7 +11,9 @@ use wasm_pkg_common::package::{PackageRef, Version}; use wasm_pkg_core::wit::WIT_DEPS_DIR; use wasm_pkg_core::{ lock::{LOCK_FILE_NAME, LockFile, LockedPackage}, - manifest::{MANIFEST_FILE_NAME, Manifest, workspace::WorkspaceRootConfig}, + manifest::{ + MANIFEST_FILE_NAME, Manifest, find_root_manifest_for_wd, workspace::WorkspaceRootConfig, + }, resolver::DependencyResolutionMap, wit::{self, OutputType}, }; @@ -155,7 +157,16 @@ pub async fn temp_wit_file(package: &PackageRef, bytes: &[u8]) -> anyhow::Result impl FetchArgs { pub async fn run(self) -> anyhow::Result<()> { let cwd = std::env::current_dir()?; - let root = Manifest::load_root_workspace(&cwd).await?; + let mut root = Manifest::load_root_workspace(&cwd).await?; + let manifest_path = find_root_manifest_for_wd(&cwd); + if root.as_ref().is_some_and(|root| { + manifest_path + .as_deref() + .and_then(Path::parent) + .is_some_and(|manifest_dir| manifest_dir != root.root_dir()) + }) { + root = None; + } let dirs = if let Some(dir) = self.dir.clone() { vec![dir] @@ -169,7 +180,10 @@ impl FetchArgs { let manifest_path = root.root_dir().join(MANIFEST_FILE_NAME); Manifest::load_from_path(manifest_path).await? } - None => Manifest::load().await?, + None => match manifest_path.as_ref() { + Some(path) => Manifest::load_from_path(path).await?, + None => Manifest::default(), + }, }; let output = self.output_type.unwrap_or_default(); @@ -182,7 +196,14 @@ impl FetchArgs { self.run_workspace_fetch(&dirs, output, &manifest, root) .await } - None => self.fetch_into_lock(&dirs, &manifest, output).await, + None => { + let lock_dir = manifest_path + .as_deref() + .and_then(Path::parent) + .unwrap_or(&cwd); + self.fetch_into_lock(&dirs, &manifest, output, lock_dir.join(LOCK_FILE_NAME)) + .await + } } } @@ -256,9 +277,10 @@ impl FetchArgs { dirs: &[PathBuf], manifest: &Manifest, output: OutputType, + lock_path: PathBuf, ) -> anyhow::Result<()> { let client = self.common.get_client().await?; - let mut lock_file = LockFile::load(false).await?; + let mut lock_file = load_or_create_lock(&lock_path).await?; let mut union: BTreeSet = BTreeSet::new(); merge_locked_packages(&mut union, std::mem::take(&mut lock_file.packages)); diff --git a/crates/wkg/tests/e2e.rs b/crates/wkg/tests/e2e.rs index 29858d1..0b9b30d 100644 --- a/crates/wkg/tests/e2e.rs +++ b/crates/wkg/tests/e2e.rs @@ -250,6 +250,26 @@ async fn fetch_workspace_packages() { } } +#[tokio::test] +async fn fetch_from_member_subdirectory_uses_member_context() { + let fixture = common::load_fixture("fetch-workspace-member").await; + let member = fixture.fixture_path.join("member/wit"); + let subdir = member.join("subdir"); + let mut command = fixture.command(); + command.current_dir(&subdir).args(["fetch", "."]); + + let status = command.status().await.expect("spawn wkg fetch"); + assert!(status.success(), "member fetch should succeed"); + assert!( + member.join("wkg.lock").exists(), + "member fetch should create a member lock file" + ); + assert!( + !fixture.fixture_path.join("wkg.lock").exists(), + "member fetch should not create a workspace lock file" + ); +} + #[tokio::test] pub async fn check() { // Use an explicit config that maps `wasi` to `wasi.dev`. diff --git a/crates/wkg/tests/fixtures/fetch-workspace-member/member/wit/subdir/world.wit b/crates/wkg/tests/fixtures/fetch-workspace-member/member/wit/subdir/world.wit new file mode 100644 index 0000000..dba860d --- /dev/null +++ b/crates/wkg/tests/fixtures/fetch-workspace-member/member/wit/subdir/world.wit @@ -0,0 +1,3 @@ +package test:subdir; + +world subdir {} diff --git a/crates/wkg/tests/fixtures/fetch-workspace-member/member/wit/wkg.toml b/crates/wkg/tests/fixtures/fetch-workspace-member/member/wit/wkg.toml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/crates/wkg/tests/fixtures/fetch-workspace-member/member/wit/wkg.toml @@ -0,0 +1 @@ + diff --git a/crates/wkg/tests/fixtures/fetch-workspace-member/member/wit/world.wit b/crates/wkg/tests/fixtures/fetch-workspace-member/member/wit/world.wit new file mode 100644 index 0000000..c8aef2a --- /dev/null +++ b/crates/wkg/tests/fixtures/fetch-workspace-member/member/wit/world.wit @@ -0,0 +1,3 @@ +package test:member; + +world member {} diff --git a/crates/wkg/tests/fixtures/fetch-workspace-member/wkg.toml b/crates/wkg/tests/fixtures/fetch-workspace-member/wkg.toml new file mode 100644 index 0000000..c03ae07 --- /dev/null +++ b/crates/wkg/tests/fixtures/fetch-workspace-member/wkg.toml @@ -0,0 +1,2 @@ +[workspace] +members = ["member/wit"]