@@ -12,7 +12,9 @@ use toml_edit::{value, Array, ArrayOfTables, Item, Table};
12
12
use url:: Url ;
13
13
14
14
use uv_cache_key:: RepositoryUrl ;
15
- use uv_configuration:: { DependencyGroupsWithDefaults , ExtrasSpecification , InstallOptions } ;
15
+ use uv_configuration:: {
16
+ BuildOptions , DependencyGroupsWithDefaults , ExtrasSpecification , InstallOptions ,
17
+ } ;
16
18
use uv_distribution_filename:: {
17
19
BuildTag , DistExtension , ExtensionError , SourceDistExtension , SourceDistFilename ,
18
20
SourceDistFilenameError , WheelFilename , WheelFilenameError ,
@@ -80,6 +82,18 @@ pub enum PylockTomlError {
80
82
PathToUrl ,
81
83
#[ error( "Failed to convert URL to path" ) ]
82
84
UrlToPath ,
85
+ #[ error( "Package `{0}` can't be installed because it doesn't have a source distribution or wheel for the current platform" ) ]
86
+ NeitherSourceDistNorWheel ( PackageName ) ,
87
+ #[ error( "Package `{0}` can't be installed because it is marked as both `--no-binary` and `--no-build`" ) ]
88
+ NoBinaryNoBuild ( PackageName ) ,
89
+ #[ error( "Package `{0}` can't be installed because it is marked as `--no-binary` but has no source distribution" ) ]
90
+ NoBinary ( PackageName ) ,
91
+ #[ error( "Package `{0}` can't be installed because it is marked as `--no-build` but has no binary distribution" ) ]
92
+ NoBuild ( PackageName ) ,
93
+ #[ error( "Package `{0}` can't be installed because the binary distribution is incompatible with the current platform" ) ]
94
+ IncompatibleWheelOnly ( PackageName ) ,
95
+ #[ error( "Package `{0}` can't be installed because it is marked as `--no-binary` but is itself a binary distribution" ) ]
96
+ NoBinaryWheelOnly ( PackageName ) ,
83
97
#[ error( transparent) ]
84
98
WheelFilename ( #[ from] WheelFilenameError ) ,
85
99
#[ error( transparent) ]
@@ -857,6 +871,7 @@ impl<'lock> PylockToml {
857
871
install_path : & Path ,
858
872
markers : & MarkerEnvironment ,
859
873
tags : & Tags ,
874
+ build_options : & BuildOptions ,
860
875
) -> Result < Resolution , PylockTomlError > {
861
876
let mut graph =
862
877
petgraph:: graph:: DiGraph :: with_capacity ( self . packages . len ( ) , self . packages . len ( ) ) ;
@@ -914,8 +929,19 @@ impl<'lock> PylockToml {
914
929
_ => { }
915
930
}
916
931
932
+ let no_binary = build_options. no_binary_package ( & package. name ) ;
933
+ let no_build = build_options. no_build_package ( & package. name ) ;
934
+ let is_wheel = package
935
+ . archive
936
+ . as_ref ( )
937
+ . map ( |archive| archive. is_wheel ( & package. name ) )
938
+ . transpose ( ) ?
939
+ . unwrap_or_default ( ) ;
940
+
917
941
// Search for a matching wheel.
918
- let dist = if let Some ( best_wheel) = package. find_best_wheel ( tags) {
942
+ let dist = if let Some ( best_wheel) =
943
+ package. find_best_wheel ( tags) . filter ( |_| !no_binary)
944
+ {
919
945
let hashes = HashDigests :: from ( best_wheel. hashes . clone ( ) ) ;
920
946
let built_dist = Dist :: Built ( BuiltDist :: Registry ( RegistryBuiltDist {
921
947
wheels : vec ! [ best_wheel. to_registry_wheel(
@@ -935,7 +961,7 @@ impl<'lock> PylockToml {
935
961
hashes,
936
962
install : true ,
937
963
}
938
- } else if let Some ( sdist) = package. sdist . as_ref ( ) {
964
+ } else if let Some ( sdist) = package. sdist . as_ref ( ) . filter ( |_| !no_build ) {
939
965
let hashes = HashDigests :: from ( sdist. hashes . clone ( ) ) ;
940
966
let sdist = Dist :: Source ( SourceDist :: Registry ( sdist. to_sdist (
941
967
install_path,
@@ -952,7 +978,7 @@ impl<'lock> PylockToml {
952
978
hashes,
953
979
install : true ,
954
980
}
955
- } else if let Some ( sdist) = package. directory . as_ref ( ) {
981
+ } else if let Some ( sdist) = package. directory . as_ref ( ) . filter ( |_| !no_build ) {
956
982
let hashes = HashDigests :: empty ( ) ;
957
983
let sdist = Dist :: Source ( SourceDist :: Directory (
958
984
sdist. to_sdist ( install_path, & package. name ) ?,
@@ -966,7 +992,7 @@ impl<'lock> PylockToml {
966
992
hashes,
967
993
install : true ,
968
994
}
969
- } else if let Some ( sdist) = package. vcs . as_ref ( ) {
995
+ } else if let Some ( sdist) = package. vcs . as_ref ( ) . filter ( |_| !no_build ) {
970
996
let hashes = HashDigests :: empty ( ) ;
971
997
let sdist = Dist :: Source ( SourceDist :: Git (
972
998
sdist. to_sdist ( install_path, & package. name ) ?,
@@ -980,7 +1006,12 @@ impl<'lock> PylockToml {
980
1006
hashes,
981
1007
install : true ,
982
1008
}
983
- } else if let Some ( dist) = package. archive . as_ref ( ) {
1009
+ } else if let Some ( dist) =
1010
+ package
1011
+ . archive
1012
+ . as_ref ( )
1013
+ . filter ( |_| if is_wheel { !no_binary } else { !no_build } )
1014
+ {
984
1015
let hashes = HashDigests :: from ( dist. hashes . clone ( ) ) ;
985
1016
let dist = dist. to_dist ( install_path, & package. name , package. version . as_ref ( ) ) ?;
986
1017
let dist = ResolvedDist :: Installable {
@@ -993,13 +1024,20 @@ impl<'lock> PylockToml {
993
1024
install : true ,
994
1025
}
995
1026
} else {
996
- // This is only reachable if the package contains a `wheels` entry (and nothing
997
- // else), but there are no wheels available for the current environment. (If the
998
- // package doesn't contain _any_ of `wheels`, `sdist`, etc., then we error in the
999
- // match above.)
1000
- //
1001
- // TODO(charlie): Include a hint, like in `uv.lock`.
1002
- return Err ( PylockTomlError :: MissingWheel ( package. name . clone ( ) ) ) ;
1027
+ return match ( no_binary, no_build) {
1028
+ ( true , true ) => Err ( PylockTomlError :: NoBinaryNoBuild ( package. name . clone ( ) ) ) ,
1029
+ ( true , false ) if is_wheel => {
1030
+ Err ( PylockTomlError :: NoBinaryWheelOnly ( package. name . clone ( ) ) )
1031
+ }
1032
+ ( true , false ) => Err ( PylockTomlError :: NoBinary ( package. name . clone ( ) ) ) ,
1033
+ ( false , true ) => Err ( PylockTomlError :: NoBuild ( package. name . clone ( ) ) ) ,
1034
+ ( false , false ) if is_wheel => {
1035
+ Err ( PylockTomlError :: IncompatibleWheelOnly ( package. name . clone ( ) ) )
1036
+ }
1037
+ ( false , false ) => Err ( PylockTomlError :: NeitherSourceDistNorWheel (
1038
+ package. name . clone ( ) ,
1039
+ ) ) ,
1040
+ } ;
1003
1041
} ;
1004
1042
1005
1043
let index = graph. add_node ( dist) ;
@@ -1441,6 +1479,31 @@ impl PylockTomlArchive {
1441
1479
return Err ( PylockTomlError :: ArchiveMissingPathUrl ( name. clone ( ) ) ) ;
1442
1480
}
1443
1481
}
1482
+
1483
+ /// Returns `true` if the [`PylockTomlArchive`] is a wheel.
1484
+ fn is_wheel ( & self , name : & PackageName ) -> Result < bool , PylockTomlError > {
1485
+ if let Some ( url) = self . url . as_ref ( ) {
1486
+ let filename = url
1487
+ . filename ( )
1488
+ . map_err ( |_| PylockTomlError :: UrlMissingFilename ( url. clone ( ) ) ) ?;
1489
+
1490
+ let ext = DistExtension :: from_path ( filename. as_ref ( ) ) ?;
1491
+ Ok ( matches ! ( ext, DistExtension :: Wheel ) )
1492
+ } else if let Some ( path) = self . path . as_ref ( ) {
1493
+ let filename = path
1494
+ . as_ref ( )
1495
+ . file_name ( )
1496
+ . and_then ( OsStr :: to_str)
1497
+ . ok_or_else ( || {
1498
+ PylockTomlError :: PathMissingFilename ( Box :: < Path > :: from ( path. clone ( ) ) )
1499
+ } ) ?;
1500
+
1501
+ let ext = DistExtension :: from_path ( filename) ?;
1502
+ Ok ( matches ! ( ext, DistExtension :: Wheel ) )
1503
+ } else {
1504
+ return Err ( PylockTomlError :: ArchiveMissingPathUrl ( name. clone ( ) ) ) ;
1505
+ }
1506
+ }
1444
1507
}
1445
1508
1446
1509
/// Convert a Jiff timestamp to a TOML datetime.
0 commit comments