pyoxidizerlib/py_packaging/
resource.rs1use {
10 anyhow::Result,
11 python_packaging::{
12 module_util::{packages_from_module_name, resolve_path_for_module},
13 resource::{
14 PythonExtensionModule, PythonModuleSource, PythonPackageDistributionResource,
15 PythonPackageResource,
16 },
17 },
18 simple_file_manifest::{FileEntry, FileManifest},
19};
20
21pub trait AddToFileManifest {
22 fn add_to_file_manifest(&self, manifest: &mut FileManifest, prefix: &str) -> Result<()>;
24}
25
26impl AddToFileManifest for PythonModuleSource {
27 fn add_to_file_manifest(&self, manifest: &mut FileManifest, prefix: &str) -> Result<()> {
28 let content = self.source.resolve_content()?;
29
30 manifest.add_file_entry(&self.resolve_path(prefix), content)?;
31
32 for package in packages_from_module_name(&self.name) {
33 let package_path = resolve_path_for_module(prefix, &package, true, None);
34
35 if !manifest.has_path(&package_path) {
36 manifest.add_file_entry(&package_path, vec![])?;
37 }
38 }
39
40 Ok(())
41 }
42}
43
44impl AddToFileManifest for PythonPackageResource {
45 fn add_to_file_manifest(&self, manifest: &mut FileManifest, prefix: &str) -> Result<()> {
46 let dest_path = self.resolve_path(prefix);
47
48 manifest.add_file_entry(&dest_path, self.data.resolve_content()?)?;
49
50 Ok(())
51 }
52}
53
54impl AddToFileManifest for PythonPackageDistributionResource {
55 fn add_to_file_manifest(&self, manifest: &mut FileManifest, prefix: &str) -> Result<()> {
56 let dest_path = self.resolve_path(prefix);
57
58 manifest.add_file_entry(&dest_path, self.data.resolve_content()?)?;
59
60 Ok(())
61 }
62}
63
64impl AddToFileManifest for PythonExtensionModule {
65 fn add_to_file_manifest(&self, manifest: &mut FileManifest, prefix: &str) -> Result<()> {
66 if let Some(data) = &self.shared_library {
67 manifest.add_file_entry(
68 &self.resolve_path(prefix),
69 FileEntry::new_from_data(data.resolve_content()?, true),
70 )?;
71 }
72
73 Ok(())
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use {super::*, itertools::Itertools, simple_file_manifest::FileData, std::path::PathBuf};
80
81 const DEFAULT_CACHE_TAG: &str = "cpython-39";
82
83 #[test]
84 fn test_source_module_add_to_manifest_top_level() -> Result<()> {
85 let mut m = FileManifest::default();
86
87 PythonModuleSource {
88 name: "foo".to_string(),
89 source: FileData::Memory(vec![]),
90 is_package: false,
91 cache_tag: DEFAULT_CACHE_TAG.to_string(),
92 is_stdlib: false,
93 is_test: false,
94 }
95 .add_to_file_manifest(&mut m, ".")?;
96
97 PythonModuleSource {
98 name: "bar".to_string(),
99 source: FileData::Memory(vec![]),
100 is_package: false,
101 cache_tag: DEFAULT_CACHE_TAG.to_string(),
102 is_stdlib: false,
103 is_test: false,
104 }
105 .add_to_file_manifest(&mut m, ".")?;
106
107 let entries = m.iter_entries().collect_vec();
108 assert_eq!(entries.len(), 2);
109 assert_eq!(entries[0].0, &PathBuf::from("./bar.py"));
110 assert_eq!(entries[1].0, &PathBuf::from("./foo.py"));
111
112 Ok(())
113 }
114
115 #[test]
116 fn test_source_module_add_to_manifest_top_level_package() -> Result<()> {
117 let mut m = FileManifest::default();
118
119 PythonModuleSource {
120 name: "foo".to_string(),
121 source: FileData::Memory(vec![]),
122 is_package: true,
123 cache_tag: DEFAULT_CACHE_TAG.to_string(),
124 is_stdlib: false,
125 is_test: false,
126 }
127 .add_to_file_manifest(&mut m, ".")?;
128
129 let entries = m.iter_entries().collect_vec();
130 assert_eq!(entries.len(), 1);
131 assert_eq!(entries[0].0, &PathBuf::from("./foo/__init__.py"));
132
133 Ok(())
134 }
135
136 #[test]
137 fn test_source_module_add_to_manifest_missing_parent() -> Result<()> {
138 let mut m = FileManifest::default();
139
140 PythonModuleSource {
141 name: "root.parent.child".to_string(),
142 source: FileData::Memory(vec![]),
143 is_package: false,
144 cache_tag: DEFAULT_CACHE_TAG.to_string(),
145 is_stdlib: false,
146 is_test: false,
147 }
148 .add_to_file_manifest(&mut m, ".")?;
149
150 let entries = m.iter_entries().collect_vec();
151 assert_eq!(entries.len(), 3);
152 assert_eq!(entries[0].0, &PathBuf::from("./root/__init__.py"));
153 assert_eq!(entries[1].0, &PathBuf::from("./root/parent/__init__.py"));
154 assert_eq!(entries[2].0, &PathBuf::from("./root/parent/child.py"));
155
156 Ok(())
157 }
158
159 #[test]
160 fn test_source_module_add_to_manifest_missing_parent_package() -> Result<()> {
161 let mut m = FileManifest::default();
162
163 PythonModuleSource {
164 name: "root.parent.child".to_string(),
165 source: FileData::Memory(vec![]),
166 is_package: true,
167 cache_tag: DEFAULT_CACHE_TAG.to_string(),
168 is_stdlib: false,
169 is_test: false,
170 }
171 .add_to_file_manifest(&mut m, ".")?;
172
173 let entries = m.iter_entries().collect_vec();
174 assert_eq!(entries.len(), 3);
175 assert_eq!(entries[0].0, &PathBuf::from("./root/__init__.py"));
176 assert_eq!(entries[1].0, &PathBuf::from("./root/parent/__init__.py"));
177 assert_eq!(
178 entries[2].0,
179 &PathBuf::from("./root/parent/child/__init__.py")
180 );
181
182 Ok(())
183 }
184}