Skip to content

Commit d7eadf2

Browse files
authored
handle when same componentize-py.toml appears twice in PYTHON_PATH (#52)
* handle when same componentize-py.toml appears twice in PYTHON_PATH In this case, we need to decide which directory "owns" the file, which affects how we derive package names relative to that directory. For example, if both `foo` and `foo/.venv/lib/python3.12/site-packages` are in `PYTHON_PATH`, and we find a componentize-py.toml file under the latter, then we'll also find it under the former. In that case, we consider the latter to be the "owner" of the file. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * bump version to 0.9.2 Signed-off-by: Joel Dice <joel.dice@fermyon.com> --------- Signed-off-by: Joel Dice <joel.dice@fermyon.com>
1 parent 82f29e1 commit d7eadf2

7 files changed

Lines changed: 59 additions & 27 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "componentize-py"
3-
version = "0.9.1"
3+
version = "0.9.2"
44
edition = "2021"
55
exclude = ["cpython"]
66

examples/cli/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ snapshot, which may differ from later revisions.
1313
## Prerequisites
1414

1515
* `Wasmtime` 16.0.0 (later versions may use a different, incompatible `wasi-cli` snapshot)
16-
* `componentize-py` 0.9.1
16+
* `componentize-py` 0.9.2
1717

1818
Below, we use [Rust](https://rustup.rs/)'s `cargo` to install `Wasmtime`. If
1919
you don't have `cargo`, you can download and install from
2020
https://github.com/bytecodealliance/wasmtime/releases/tag/v16.0.0.
2121

2222
```
2323
cargo install --version 16.0.0 wasmtime-cli
24-
pip install componentize-py==0.9.1
24+
pip install componentize-py==0.9.2
2525
```
2626

2727
## Running the demo

examples/http/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ which may differ from later revisions.
1414
## Prerequisites
1515

1616
* `Wasmtime` 16.0.0 (later versions may use a different, incompatible `wasi-http` snapshot)
17-
* `componentize-py` 0.9.1
17+
* `componentize-py` 0.9.2
1818

1919
Below, we use [Rust](https://rustup.rs/)'s `cargo` to install `Wasmtime`. If
2020
you don't have `cargo`, you can download and install from
2121
https://github.com/bytecodealliance/wasmtime/releases/tag/v16.0.0.
2222

2323
```
2424
cargo install --version 16.0.0 wasmtime-cli
25-
pip install componentize-py==0.9.1
25+
pip install componentize-py==0.9.2
2626
```
2727

2828
## Running the demo

examples/matrix-math/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ within a guest component.
1111
## Prerequisites
1212

1313
* `wasmtime` 16.0.0 (later versions may use a different, incompatible `wasi-cli` snapshot)
14-
* `componentize-py` 0.9.1
14+
* `componentize-py` 0.9.2
1515
* `NumPy`, built for WASI
1616

1717
Note that we use an unofficial build of NumPy since the upstream project does
@@ -23,7 +23,7 @@ https://github.com/bytecodealliance/wasmtime/releases/tag/v16.0.0.
2323

2424
```
2525
cargo install --version 16.0.0 wasmtime-cli
26-
pip install componentize-py==0.9.1
26+
pip install componentize-py==0.9.2
2727
curl -OL https://github.com/dicej/wasi-wheels/releases/download/v0.0.1/numpy-wasi.tar.gz
2828
tar xf numpy-wasi.tar.gz
2929
```

examples/tcp/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ snapshot, which may differ from later revisions.
1414
## Prerequisites
1515

1616
* `Wasmtime` 16.0.0 (later versions may use a different, incompatible `wasi-cli` snapshot)
17-
* `componentize-py` 0.9.1
17+
* `componentize-py` 0.9.2
1818

1919
Below, we use [Rust](https://rustup.rs/)'s `cargo` to install `Wasmtime`. If
2020
you don't have `cargo`, you can download and install from
2121
https://github.com/bytecodealliance/wasmtime/releases/tag/v16.0.0.
2222

2323
```
2424
cargo install --version 16.0.0 wasmtime-cli
25-
pip install componentize-py==0.9.1
25+
pip install componentize-py==0.9.2
2626
```
2727

2828
## Running the demo

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ features = ["pyo3/extension-module"]
77

88
[project]
99
name = "componentize-py"
10-
version = "0.9.1"
10+
version = "0.9.2"
1111
description = "Tool to package Python applications as WebAssembly components"
1212
readme = "README.md"
1313
license = { file = "LICENSE" }

src/lib.rs

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -206,13 +206,18 @@ pub async fn componentize(
206206
let mut library_path = Vec::with_capacity(python_path.len());
207207
for path in python_path {
208208
let mut libraries = Vec::new();
209-
search_directory(Path::new(path), &mut libraries, &mut raw_config)?;
209+
search_directory(
210+
Path::new(path),
211+
Path::new(path),
212+
&mut libraries,
213+
&mut raw_config,
214+
)?;
210215
library_path.push((*path, libraries));
211216
}
212217

213-
let config = if let Some((config_path, raw)) = raw_config {
218+
let config = if let Some((config_root, config_path, raw)) = raw_config {
214219
let config = ComponentizePyConfig::try_from((config_path.deref(), raw))?;
215-
Some((config_path, config))
220+
Some((config_root, config_path, config))
216221
} else {
217222
None
218223
};
@@ -221,7 +226,7 @@ pub async fn componentize(
221226
path.to_owned()
222227
} else if let Some((config_path, wit_path)) = config
223228
.as_ref()
224-
.and_then(|(p, c)| c.wit_directory.as_deref().map(|f| (p, f)))
229+
.and_then(|(_, p, c)| c.wit_directory.as_deref().map(|f| (p, f)))
225230
{
226231
config_path.join(wit_path)
227232
} else {
@@ -369,22 +374,29 @@ pub async fn componentize(
369374

370375
let world_dir = tempfile::tempdir()?;
371376

372-
let (world_dir_mounts, world_module) = if let Some((config_path, binding_path)) = config
373-
.as_ref()
374-
.and_then(|(p, c)| c.bindings.as_deref().map(|f| (p, f)))
377+
let (world_dir_mounts, world_module) = if let Some((config_root, config_path, binding_path)) =
378+
config
379+
.as_ref()
380+
.and_then(|(r, p, c)| c.bindings.as_deref().map(|f| (r, p, f)))
375381
{
376382
summary.generate_code(world_dir.path(), false)?;
377383

378384
let paths = python_path
379385
.iter()
380386
.enumerate()
381387
.map(|(index, dir)| {
382-
Ok(config_path
383-
.canonicalize()?
384-
.join(binding_path)
385-
.strip_prefix(Path::new(dir).canonicalize()?)
386-
.ok()
387-
.map(|p| (index, p.to_str().unwrap().to_owned())))
388+
let dir = Path::new(dir).canonicalize()?;
389+
let config_root = config_root.canonicalize()?;
390+
Ok(if config_root == dir {
391+
config_path
392+
.canonicalize()?
393+
.join(binding_path)
394+
.strip_prefix(dir)
395+
.ok()
396+
.map(|p| (index, p.to_str().unwrap().to_owned()))
397+
} else {
398+
None
399+
})
388400
})
389401
.filter_map(Result::transpose)
390402
.collect::<Result<Vec<_>>>()?;
@@ -590,22 +602,42 @@ fn add_wasi_and_stubs(
590602
}
591603

592604
fn search_directory(
605+
root: &Path,
593606
path: &Path,
594607
libraries: &mut Vec<PathBuf>,
595-
config: &mut Option<(PathBuf, RawComponentizePyConfig)>,
608+
config: &mut Option<(PathBuf, PathBuf, RawComponentizePyConfig)>,
596609
) -> Result<()> {
597610
if path.is_dir() {
598611
for entry in fs::read_dir(path)? {
599-
search_directory(&entry?.path(), libraries, config)?;
612+
search_directory(root, &entry?.path(), libraries, config)?;
600613
}
601614
} else if let Some(name) = path.file_name().and_then(|name| name.to_str()) {
602615
if name.ends_with(NATIVE_EXTENSION_SUFFIX) {
603616
libraries.push(path.to_owned());
604617
} else if name == "componentize-py.toml" {
605-
if config.is_some() {
606-
bail!("multiple componentize-py.toml files found, which is not yet supported");
618+
let do_update = if let Some((existing_root, existing_path, _)) = config {
619+
let path = path.canonicalize()?;
620+
let existing_path = existing_path.join("componentize-py.toml").canonicalize()?;
621+
if path != existing_path {
622+
bail!(
623+
"multiple componentize-py.toml files found, \
624+
which is not yet supported: {} and {}",
625+
existing_path.display(),
626+
path.display()
627+
);
628+
}
629+
630+
// When one directory in `PYTHON_PATH` is a subdirectory of the other, we consider the subdirectory
631+
// to be the true owner of the file. This is important later, when we derive a package name by
632+
// stripping the root directory from the file path.
633+
root.canonicalize()? > existing_root.canonicalize()?
607634
} else {
635+
true
636+
};
637+
638+
if do_update {
608639
*config = Some((
640+
root.to_owned(),
609641
path.parent().unwrap().to_owned(),
610642
toml::from_str::<RawComponentizePyConfig>(&fs::read_to_string(path)?)?,
611643
));

0 commit comments

Comments
 (0)