|
11 | 11 | prelink::{embedded_helper_utils, embedded_python_standard_library}, |
12 | 12 | serde::Deserialize, |
13 | 13 | std::{ |
14 | | - collections::{HashMap, HashSet}, |
| 14 | + collections::HashMap, |
15 | 15 | env, fs, |
16 | 16 | io::Cursor, |
17 | 17 | iter, |
@@ -49,7 +49,6 @@ mod summary; |
49 | 49 | mod test; |
50 | 50 | mod util; |
51 | 51 |
|
52 | | -static NATIVE_EXTENSION_SUFFIX: &str = ".cpython-312-wasm32-wasi.so"; |
53 | 52 |
|
54 | 53 | wasmtime::component::bindgen!({ |
55 | 54 | path: "wit", |
@@ -213,73 +212,14 @@ pub async fn componentize( |
213 | 212 | .filter_map(|&s| Path::new(s).exists().then_some(s)) |
214 | 213 | .collect::<Vec<_>>(); |
215 | 214 |
|
216 | | - let embedded_python_standard_lib = embedded_python_standard_library().unwrap(); |
217 | | - let embedded_helper_utils = embedded_helper_utils().unwrap(); |
218 | | - |
219 | | - // Search `python_path` for native extension libraries and/or componentize-py.toml files. Packages containing |
220 | | - // the latter may contain their own WIT files defining their own worlds (in addition to what the caller |
221 | | - // specified as paramters), which we'll try to match up with `module_worlds` in the next step. |
222 | | - let mut raw_configs: Vec<crate::ConfigContext<crate::RawComponentizePyConfig>> = Vec::new(); |
223 | | - let mut library_path: Vec<(&str, Vec<std::path::PathBuf>)> = |
224 | | - Vec::with_capacity(python_path.len()); |
225 | | - for path in python_path { |
226 | | - let mut libraries = Vec::new(); |
227 | | - search_directory( |
228 | | - Path::new(path), |
229 | | - Path::new(path), |
230 | | - &mut libraries, |
231 | | - &mut raw_configs, |
232 | | - &mut HashSet::new(), |
233 | | - )?; |
234 | | - library_path.push((*path, libraries)); |
235 | | - } |
236 | | - |
237 | | - let mut libraries = prelink::bundle_libraries(library_path)?; |
238 | | - |
239 | | - // Validate the paths parsed from any componentize-py.toml files discovered above and match them up with |
240 | | - // `module_worlds` entries. Note that we use an `IndexMap` to preserve the order specified in `module_worlds`, |
241 | | - // which is required to be topologically sorted with respect to package dependencies. |
242 | | - // |
243 | | - // For any packages which contain componentize-py.toml files but no corresponding `module_worlds` entry, we use |
244 | | - // the `world` parameter as a default. |
245 | | - let configs = { |
246 | | - let mut configs = raw_configs |
247 | | - .into_iter() |
248 | | - .map(|raw_config| { |
249 | | - let config = |
250 | | - ComponentizePyConfig::try_from((raw_config.path.deref(), raw_config.config))?; |
251 | | - |
252 | | - Ok(( |
253 | | - raw_config.module.clone(), |
254 | | - ConfigContext { |
255 | | - module: raw_config.module, |
256 | | - root: raw_config.root, |
257 | | - path: raw_config.path, |
258 | | - config, |
259 | | - }, |
260 | | - )) |
261 | | - }) |
262 | | - .collect::<Result<HashMap<_, _>>>()?; |
263 | | - |
264 | | - let mut ordered = IndexMap::new(); |
265 | | - for (module, world) in module_worlds { |
266 | | - if let Some(config) = configs.remove(*module) { |
267 | | - ordered.insert((*module).to_owned(), (config, Some(*world))); |
268 | | - } else { |
269 | | - bail!("no `componentize-py.toml` file found for module `{module}`"); |
270 | | - } |
271 | | - } |
| 215 | + let embedded_python_standard_lib = embedded_python_standard_library()?; |
| 216 | + let embedded_helper_utils = embedded_helper_utils()?; |
272 | 217 |
|
273 | | - for (module, config) in configs { |
274 | | - ordered.insert(module, (config, world)); |
275 | | - } |
| 218 | + let (configs, mut libraries) = prelink::search_for_libraries_and_configs(python_path, module_worlds)?; |
276 | 219 |
|
277 | | - ordered |
278 | | - }; |
279 | 220 |
|
280 | 221 | // Next, iterate over all the WIT directories, merging them into a single `Resolve`, and matching Python |
281 | 222 | // packages to `WorldId`s. |
282 | | - |
283 | 223 | let (mut resolve, mut main_world) = if let Some(path) = wit_path { |
284 | 224 | let (resolve, world) = parse_wit(path, world)?; |
285 | 225 | (Some(resolve), Some(world)) |
@@ -735,83 +675,8 @@ fn add_wasi_and_stubs( |
735 | 675 | Ok(()) |
736 | 676 | } |
737 | 677 |
|
738 | | -fn search_directory( |
739 | | - root: &Path, |
740 | | - path: &Path, |
741 | | - libraries: &mut Vec<PathBuf>, |
742 | | - configs: &mut Vec<ConfigContext<RawComponentizePyConfig>>, |
743 | | - modules_seen: &mut HashSet<String>, |
744 | | -) -> Result<()> { |
745 | | - if path.is_dir() { |
746 | | - for entry in fs::read_dir(path)? { |
747 | | - search_directory(root, &entry?.path(), libraries, configs, modules_seen)?; |
748 | | - } |
749 | | - } else if let Some(name) = path.file_name().and_then(|name| name.to_str()) { |
750 | | - if name.ends_with(NATIVE_EXTENSION_SUFFIX) { |
751 | | - libraries.push(path.to_owned()); |
752 | | - } else if name == "componentize-py.toml" { |
753 | | - let root = root.canonicalize()?; |
754 | | - let path = path.canonicalize()?; |
755 | | - |
756 | | - let module = module_name(&root, &path) |
757 | | - .ok_or_else(|| anyhow!("unable to determine module name for {}", path.display()))?; |
758 | | - |
759 | | - let mut push = true; |
760 | | - for existing in &mut *configs { |
761 | | - if path == existing.path.join("componentize-py.toml") { |
762 | | - // When one directory in `PYTHON_PATH` is a subdirectory of the other, we consider the |
763 | | - // subdirectory to be the true owner of the file. This is important later, when we derive a |
764 | | - // package name by stripping the root directory from the file path. |
765 | | - if root > existing.root { |
766 | | - module.clone_into(&mut existing.module); |
767 | | - root.clone_into(&mut existing.root); |
768 | | - path.parent().unwrap().clone_into(&mut existing.path); |
769 | | - } |
770 | | - push = false; |
771 | | - break; |
772 | | - } else { |
773 | | - // If we find a componentize-py.toml file under a Python module which will not be used because |
774 | | - // we already found a version of that module in an earlier `PYTHON_PATH` directory, we'll |
775 | | - // ignore the latest one. |
776 | | - // |
777 | | - // For example, if the module `foo_sdk` appears twice in `PYTHON_PATH`, and both versions have |
778 | | - // a componentize-py.toml file, we'll ignore the second one just as Python will ignore the |
779 | | - // second module. |
780 | | - |
781 | | - if modules_seen.contains(&module) { |
782 | | - bail!("multiple `componentize-py.toml` files found in module `{module}`"); |
783 | | - } |
784 | 678 |
|
785 | | - modules_seen.insert(module.clone()); |
786 | 679 |
|
787 | | - if module == existing.module { |
788 | | - push = false; |
789 | | - break; |
790 | | - } |
791 | | - } |
792 | | - } |
793 | | - |
794 | | - if push { |
795 | | - configs.push(ConfigContext { |
796 | | - module, |
797 | | - root: root.to_owned(), |
798 | | - path: path.parent().unwrap().to_owned(), |
799 | | - config: toml::from_str::<RawComponentizePyConfig>(&fs::read_to_string(path)?)?, |
800 | | - }); |
801 | | - } |
802 | | - } |
803 | | - } |
804 | | - |
805 | | - Ok(()) |
806 | | -} |
807 | | - |
808 | | -fn module_name(root: &Path, path: &Path) -> Option<String> { |
809 | | - if let [first, _, ..] = &path.strip_prefix(root).ok()?.iter().collect::<Vec<_>>()[..] { |
810 | | - first.to_str().map(|s| s.to_owned()) |
811 | | - } else { |
812 | | - None |
813 | | - } |
814 | | -} |
815 | 680 |
|
816 | 681 | fn add_wasi_imports<'a>( |
817 | 682 | module: &'a [u8], |
|
0 commit comments