@@ -21,6 +21,7 @@ use async_once_cell::OnceCell as AsyncCell;
21
21
pub use environment:: Environment ;
22
22
pub use has_project_ref:: HasProjectRef ;
23
23
use indexmap:: Equivalent ;
24
+ use itertools:: Itertools ;
24
25
use miette:: IntoDiagnostic ;
25
26
use once_cell:: sync:: OnceCell ;
26
27
use pixi_config:: Config ;
@@ -534,15 +535,28 @@ impl Project {
534
535
. map ( |pc| pc. channel . clone ( ) . into_channel ( channel_config) )
535
536
. collect ( ) ;
536
537
538
+ let feature_channels: HashSet < _ > = manifest
539
+ . parsed
540
+ . features
541
+ . values ( )
542
+ . flat_map ( |feature| feature. channels . iter ( ) )
543
+ . flatten ( )
544
+ . map ( |pc| pc. channel . clone ( ) . into_channel ( channel_config) )
545
+ . collect ( ) ;
546
+
547
+ let project_and_feature_channels: HashSet < _ > =
548
+ project_channels. union ( & feature_channels) . collect ( ) ;
549
+
537
550
for channel in channel_to_location_map. keys ( ) {
538
- if !project_channels . contains ( channel) {
539
- let channels = project_channels
551
+ if !project_and_feature_channels . contains ( channel) {
552
+ let channels = project_and_feature_channels
540
553
. iter ( )
541
554
. map ( |c| c. name . clone ( ) . unwrap_or_else ( || c. base_url . to_string ( ) ) )
555
+ . sorted ( )
542
556
. collect :: < Vec < _ > > ( )
543
557
. join ( ", " ) ;
544
558
miette:: bail!(
545
- "Defined conda-pypi-map channel: {} is missing from the channels, which are: {}" ,
559
+ "conda-pypi-map is defined: the {} is missing from the channels array , which currently are: {}" ,
546
560
console:: style(
547
561
channel
548
562
. name
@@ -954,4 +968,38 @@ mod tests {
954
968
& MappingLocation :: Path ( PathBuf :: from( "mapping.json" ) )
955
969
) ;
956
970
}
971
+
972
+ #[ test]
973
+ fn test_mapping_ensure_feature_channels_also_checked ( ) {
974
+ let file_contents = r#"
975
+ [project]
976
+ name = "foo"
977
+ channels = ["conda-forge", "pytorch"]
978
+ platforms = []
979
+ conda-pypi-map = {custom-feature-channel = "https://github.com/prefix-dev/parselmouth/blob/main/files/compressed_mapping.json"}
980
+
981
+ [feature.a]
982
+ channels = ["custom-feature-channel"]
983
+ "# ;
984
+ let manifest = Manifest :: from_str ( Path :: new ( "pixi.toml" ) , file_contents) . unwrap ( ) ;
985
+ let project = Project :: from_manifest ( manifest) ;
986
+
987
+ assert ! ( project. pypi_name_mapping_source( ) . is_ok( ) ) ;
988
+
989
+ let non_existing_channel = r#"
990
+ [project]
991
+ name = "foo"
992
+ channels = ["conda-forge", "pytorch"]
993
+ platforms = []
994
+ conda-pypi-map = {non-existing-channel = "https://github.com/prefix-dev/parselmouth/blob/main/files/compressed_mapping.json"}
995
+ "# ;
996
+ let manifest = Manifest :: from_str ( Path :: new ( "pixi.toml" ) , non_existing_channel) . unwrap ( ) ;
997
+ let project = Project :: from_manifest ( manifest) ;
998
+
999
+ // We output error message with bold channel name,
1000
+ // so we need to disable colors for snapshot
1001
+ console:: set_colors_enabled ( false ) ;
1002
+
1003
+ insta:: assert_snapshot!( project. pypi_name_mapping_source( ) . unwrap_err( ) ) ;
1004
+ }
957
1005
}
0 commit comments