From 4cb8694261771f28f7a81755680cca326a2621a2 Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Mon, 22 May 2023 19:45:55 +0800 Subject: [PATCH] Use a polyfill to make the JS tests pass --- .../src/runtime/resolver/filesystem_source.rs | 5 +- .../src/runtime/resolver/in_memory_source.rs | 6 ++- lib/wasi/src/runtime/resolver/inputs.rs | 7 +-- lib/wasi/src/runtime/resolver/mod.rs | 5 +- lib/wasi/src/runtime/resolver/polyfills.rs | 50 +++++++++++++++++++ lib/wasi/src/state/env.rs | 8 ++- 6 files changed, 69 insertions(+), 12 deletions(-) create mode 100644 lib/wasi/src/runtime/resolver/polyfills.rs diff --git a/lib/wasi/src/runtime/resolver/filesystem_source.rs b/lib/wasi/src/runtime/resolver/filesystem_source.rs index 2a2aacde2f5..d6bcccfe4f2 100644 --- a/lib/wasi/src/runtime/resolver/filesystem_source.rs +++ b/lib/wasi/src/runtime/resolver/filesystem_source.rs @@ -1,5 +1,4 @@ use anyhow::{Context, Error}; -use url::Url; use webc::compat::Container; use crate::runtime::resolver::{ @@ -29,8 +28,8 @@ impl Source for FileSystemSource { let container = Container::from_disk(&path) .with_context(|| format!("Unable to parse \"{}\"", path.display()))?; - let url = Url::from_file_path(&path) - .map_err(|_| anyhow::anyhow!("Unable to turn \"{}\" into a URL", path.display()))?; + let url = crate::runtime::resolver::polyfills::url_from_file_path(&path) + .ok_or_else(|| anyhow::anyhow!("Unable to turn \"{}\" into a URL", path.display()))?; let summary = PackageSummary { pkg: PackageInfo::from_manifest(container.manifest())?, diff --git a/lib/wasi/src/runtime/resolver/in_memory_source.rs b/lib/wasi/src/runtime/resolver/in_memory_source.rs index adea1cd45af..e34df010b3d 100644 --- a/lib/wasi/src/runtime/resolver/in_memory_source.rs +++ b/lib/wasi/src/runtime/resolver/in_memory_source.rs @@ -107,7 +107,6 @@ impl Source for InMemorySource { #[cfg(test)] mod tests { use tempfile::TempDir; - use url::Url; use crate::runtime::resolver::{ inputs::{DistributionInfo, PackageInfo}, @@ -162,7 +161,10 @@ mod tests { entrypoint: None, }, dist: DistributionInfo { - webc: Url::from_file_path(bash.canonicalize().unwrap()).unwrap(), + webc: crate::runtime::resolver::polyfills::url_from_file_path( + bash.canonicalize().unwrap() + ) + .unwrap(), webc_sha256: [ 7, 226, 190, 131, 173, 231, 130, 245, 207, 185, 51, 189, 86, 85, 222, 37, 27, 163, 170, 27, 25, 24, 211, 136, 186, 233, 174, 119, 66, 15, 134, 9 diff --git a/lib/wasi/src/runtime/resolver/inputs.rs b/lib/wasi/src/runtime/resolver/inputs.rs index 6447777bcd6..8b0b277522c 100644 --- a/lib/wasi/src/runtime/resolver/inputs.rs +++ b/lib/wasi/src/runtime/resolver/inputs.rs @@ -134,9 +134,10 @@ impl PackageSummary { let path = path.as_ref().canonicalize()?; let container = Container::from_disk(&path)?; let webc_sha256 = WebcHash::for_file(&path)?; - let url = Url::from_file_path(&path).map_err(|_| { - anyhow::anyhow!("Unable to turn \"{}\" into a file:// URL", path.display()) - })?; + let url = + crate::runtime::resolver::polyfills::url_from_file_path(&path).ok_or_else(|| { + anyhow::anyhow!("Unable to turn \"{}\" into a file:// URL", path.display()) + })?; let pkg = PackageInfo::from_manifest(container.manifest())?; let dist = DistributionInfo { diff --git a/lib/wasi/src/runtime/resolver/mod.rs b/lib/wasi/src/runtime/resolver/mod.rs index 311536b3e1d..58b05f0becf 100644 --- a/lib/wasi/src/runtime/resolver/mod.rs +++ b/lib/wasi/src/runtime/resolver/mod.rs @@ -1,3 +1,4 @@ +mod filesystem_source; mod in_memory_source; mod inputs; mod multi_source_registry; @@ -5,13 +6,13 @@ mod outputs; mod registry; mod resolve; mod source; +pub(crate) mod polyfills; mod wapm_source; mod web_source; -mod filesystem_source; pub use self::{ - in_memory_source::InMemorySource, filesystem_source::FileSystemSource, + in_memory_source::InMemorySource, inputs::{ Command, Dependency, DistributionInfo, PackageInfo, PackageSpecifier, PackageSummary, WebcHash, diff --git a/lib/wasi/src/runtime/resolver/polyfills.rs b/lib/wasi/src/runtime/resolver/polyfills.rs new file mode 100644 index 00000000000..7f7614ab6a1 --- /dev/null +++ b/lib/wasi/src/runtime/resolver/polyfills.rs @@ -0,0 +1,50 @@ +use std::path::Path; + +use url::Url; + +/// Polyfill for [`Url::from_file_path()`] that works on `wasm32-unknown-unknown`. +pub(crate) fn url_from_file_path(path: impl AsRef) -> Option { + let path = path.as_ref(); + + if !path.is_absolute() { + return None; + } + + let mut buffer = String::new(); + + for component in path { + if !buffer.ends_with('/') { + buffer.push('/'); + } + + buffer.push_str(component.to_str()?); + } + + buffer.insert_str(0, "file://"); + + buffer.parse().ok() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(unix)] + fn behaviour_is_identical() { + let inputs = [ + "/", + "/path", + "/path/to/file.txt", + "./path/to/file.txt", + ".", + "", + ]; + + for path in inputs { + let got = url_from_file_path(path); + let expected = Url::from_file_path(path).ok(); + assert_eq!(got, expected, "Mismatch for \"{path}\""); + } + } +} diff --git a/lib/wasi/src/state/env.rs b/lib/wasi/src/state/env.rs index b09f647fad3..7015691ff48 100644 --- a/lib/wasi/src/state/env.rs +++ b/lib/wasi/src/state/env.rs @@ -856,10 +856,14 @@ impl WasiEnv { /// Make all the commands in a [`BinaryPackage`] available to the WASI /// instance. /// - /// The [`BinaryPackageCommand::atom()`] will be saved to `/bin/command`. + /// The [`BinaryPackageCommand::atom()`][cmd-atom] will be saved to + /// `/bin/command`. /// /// This will also merge the command's filesystem - /// ([`BinaryPackage::webc_fs`]) into the current filesystem. + /// ([`BinaryPackage::webc_fs`][pkg-fs]) into the current filesystem. + /// + /// [cmd-atom]: crate::bin_factory::BinaryPackageCommand::atom() + /// [pkg-fs]: crate::bin_factory::BinaryPackage::webc_fs pub fn use_package(&self, pkg: &BinaryPackage) -> Result<(), WasiStateCreationError> { // PERF: We should avoid all these copies in the WasiFsRoot::Backing case.