@@ -149,6 +149,7 @@ fn write_dist_info_uses_license_file_sources() -> Result<()> {
149149}
150150
151151#[ test]
152+ #[ serial_test:: serial]
152153fn write_dist_info_rejects_absolute_license_paths ( ) {
153154 use pep440_rs:: Version ;
154155 use std:: str:: FromStr ;
@@ -173,3 +174,136 @@ fn write_dist_info_rejects_absolute_license_paths() {
173174 "unexpected error: {err:#}"
174175 ) ;
175176}
177+
178+ #[ test]
179+ #[ serial_test:: serial]
180+ fn write_dist_info_respects_metadata_directory_env_var ( ) -> Result < ( ) > {
181+ use pep440_rs:: Version ;
182+ use std:: str:: FromStr ;
183+
184+ let temp_dir = tempfile:: tempdir ( ) ?;
185+ let pyproject_dir = temp_dir. path ( ) . join ( "crate" ) ;
186+ fs_err:: create_dir_all ( & pyproject_dir) ?;
187+
188+ let metadata = Metadata24 :: new ( "test-pkg" . to_string ( ) , Version :: from_str ( "1.0.0" ) . unwrap ( ) ) ;
189+ let dist_info_name = "test_pkg-1.0.0.dist-info" ;
190+
191+ // Create a pre-generated .dist-info directory with custom METADATA
192+ let metadata_dir = temp_dir. path ( ) . join ( "metadata" ) ;
193+ let pre_existing_dir = metadata_dir. join ( dist_info_name) ;
194+ fs_err:: create_dir_all ( & pre_existing_dir) ?;
195+
196+ let custom_metadata =
197+ "Metadata-Version: 2.4\n Name: test-pkg\n Version: 1.0.0\n Classifier: Custom :: Classifier\n " ;
198+ fs_err:: write ( pre_existing_dir. join ( "METADATA" ) , custom_metadata) ?;
199+ fs_err:: write ( pre_existing_dir. join ( "WHEEL" ) , "should be overwritten" ) ?;
200+ fs_err:: write ( pre_existing_dir. join ( "RECORD" ) , "should be skipped" ) ?;
201+ fs_err:: write (
202+ pre_existing_dir. join ( "entry_points.txt" ) ,
203+ "[console_scripts]\n foo=bar:main\n " ,
204+ ) ?;
205+
206+ // Create a licenses/ subdirectory
207+ let licenses_dir = pre_existing_dir. join ( "licenses" ) ;
208+ fs_err:: create_dir_all ( & licenses_dir) ?;
209+ fs_err:: write ( licenses_dir. join ( "LICENSE" ) , "MIT License" ) ?;
210+
211+ // Per PEP 517, metadata_directory points to the .dist-info directory itself
212+ // SAFETY: This test is serialized and the env var is removed before returning.
213+ unsafe { std:: env:: set_var ( "MATURIN_PEP517_METADATA_DIR" , & pre_existing_dir) } ;
214+ let mut writer = VirtualWriter :: new ( MockWriter :: default ( ) , Override :: empty ( ) ) ;
215+ let tags = & [ "cp310-cp310-manylinux_2_17_x86_64" . to_string ( ) ] ;
216+ let result = write_dist_info ( & mut writer, & pyproject_dir, & metadata, tags) ;
217+ unsafe { std:: env:: remove_var ( "MATURIN_PEP517_METADATA_DIR" ) } ;
218+ result?;
219+
220+ let files = writer. finish ( ) ?;
221+
222+ // METADATA should be the custom one, not regenerated
223+ let metadata_key = Path :: new ( dist_info_name) . join ( "METADATA" ) ;
224+ assert_eq ! (
225+ str :: from_utf8( & files[ & metadata_key] ) . unwrap( ) ,
226+ custom_metadata
227+ ) ;
228+
229+ // WHEEL should be regenerated with correct tags, not the pre-existing content
230+ let wheel_key = Path :: new ( dist_info_name) . join ( "WHEEL" ) ;
231+ let wheel_content = str:: from_utf8 ( & files[ & wheel_key] ) . unwrap ( ) ;
232+ assert ! (
233+ wheel_content. contains( "Tag: cp310-cp310-manylinux_2_17_x86_64" ) ,
234+ "WHEEL should contain the correct tag, got: {wheel_content}"
235+ ) ;
236+ assert ! (
237+ !wheel_content. contains( "should be overwritten" ) ,
238+ "WHEEL should be regenerated, not copied"
239+ ) ;
240+
241+ // RECORD should not be present (it's generated later by WheelWriter)
242+ let record_key = Path :: new ( dist_info_name) . join ( "RECORD" ) ;
243+ assert ! ( !files. contains_key( & record_key) ) ;
244+
245+ // entry_points.txt should be copied
246+ let ep_key = Path :: new ( dist_info_name) . join ( "entry_points.txt" ) ;
247+ assert_eq ! (
248+ str :: from_utf8( & files[ & ep_key] ) . unwrap( ) ,
249+ "[console_scripts]\n foo=bar:main\n "
250+ ) ;
251+
252+ // License file from subdirectory should be copied
253+ let license_key = Path :: new ( dist_info_name) . join ( "licenses" ) . join ( "LICENSE" ) ;
254+ assert_eq ! ( str :: from_utf8( & files[ & license_key] ) . unwrap( ) , "MIT License" ) ;
255+
256+ Ok ( ( ) )
257+ }
258+
259+ #[ test]
260+ #[ serial_test:: serial]
261+ fn write_dist_info_metadata_dir_as_parent_directory ( ) -> Result < ( ) > {
262+ use pep440_rs:: Version ;
263+ use std:: str:: FromStr ;
264+
265+ let temp_dir = tempfile:: tempdir ( ) ?;
266+ let pyproject_dir = temp_dir. path ( ) . join ( "crate" ) ;
267+ fs_err:: create_dir_all ( & pyproject_dir) ?;
268+
269+ let metadata = Metadata24 :: new ( "test-pkg" . to_string ( ) , Version :: from_str ( "1.0.0" ) . unwrap ( ) ) ;
270+ let dist_info_name = "test_pkg-1.0.0.dist-info" ;
271+
272+ // Create a parent directory containing the .dist-info subdirectory
273+ let parent_dir = temp_dir. path ( ) . join ( "metadata" ) ;
274+ let pre_existing_dir = parent_dir. join ( dist_info_name) ;
275+ fs_err:: create_dir_all ( & pre_existing_dir) ?;
276+
277+ let custom_metadata =
278+ "Metadata-Version: 2.4\n Name: test-pkg\n Version: 1.0.0\n Classifier: Custom :: Classifier\n " ;
279+ fs_err:: write ( pre_existing_dir. join ( "METADATA" ) , custom_metadata) ?;
280+ fs_err:: write ( pre_existing_dir. join ( "WHEEL" ) , "should be overwritten" ) ?;
281+
282+ // Set env var to the parent directory (PEP 517 spec form)
283+ // SAFETY: This test is serialized and the env var is removed before returning.
284+ unsafe { std:: env:: set_var ( "MATURIN_PEP517_METADATA_DIR" , & parent_dir) } ;
285+ let mut writer = VirtualWriter :: new ( MockWriter :: default ( ) , Override :: empty ( ) ) ;
286+ let tags = & [ "cp310-cp310-manylinux_2_17_x86_64" . to_string ( ) ] ;
287+ let result = write_dist_info ( & mut writer, & pyproject_dir, & metadata, tags) ;
288+ unsafe { std:: env:: remove_var ( "MATURIN_PEP517_METADATA_DIR" ) } ;
289+ result?;
290+
291+ let files = writer. finish ( ) ?;
292+
293+ // METADATA should be the custom one
294+ let metadata_key = Path :: new ( dist_info_name) . join ( "METADATA" ) ;
295+ assert_eq ! (
296+ str :: from_utf8( & files[ & metadata_key] ) . unwrap( ) ,
297+ custom_metadata
298+ ) ;
299+
300+ // WHEEL should be regenerated
301+ let wheel_key = Path :: new ( dist_info_name) . join ( "WHEEL" ) ;
302+ let wheel_content = str:: from_utf8 ( & files[ & wheel_key] ) . unwrap ( ) ;
303+ assert ! (
304+ wheel_content. contains( "Tag: cp310-cp310-manylinux_2_17_x86_64" ) ,
305+ "WHEEL should contain the correct tag, got: {wheel_content}"
306+ ) ;
307+
308+ Ok ( ( ) )
309+ }
0 commit comments