@@ -18,7 +18,12 @@ pub struct Headers {
1818
1919impl Headers {
2020 pub fn get_version ( path : & Path ) -> Option < String > {
21- get_version ( path)
21+ let mut path = path. to_path_buf ( ) ;
22+ let bin = if cfg ! ( windows) { "Scripts" } else { "bin" } ;
23+ if path. ends_with ( bin) {
24+ path. pop ( ) ;
25+ }
26+ get_version ( & path, None )
2227 }
2328}
2429
@@ -28,23 +33,16 @@ impl Headers {
2833// /* Version as a string */
2934// #define PY_VERSION "3.10.2"
3035// /*--end constants--*/
31- pub fn get_version ( path : & Path ) -> Option < String > {
32- let mut path = path. to_path_buf ( ) ;
33- let bin = if cfg ! ( windows) { "Scripts" } else { "bin" } ;
34- if path. ends_with ( bin) {
35- path. pop ( ) ;
36- }
36+ pub fn get_version ( sys_prefix : & Path , pyver : Option < ( u64 , u64 ) > ) -> Option < String > {
3737 // Generally the files are in Headers in windows and include in unix
3838 // However they can also be in Headers on Mac (command line tools python, hence make no assumptions)
39- for headers_path in [ path. join ( "Headers" ) , path. join ( "include" ) ] {
40- let patchlevel_h = headers_path. join ( "patchlevel.h" ) ;
41- let mut contents = "" . to_string ( ) ;
42- if let Ok ( result) = fs:: read_to_string ( patchlevel_h) {
43- contents = result;
44- } else if !headers_path. exists ( ) {
45- // TODO: Remove this check, unnecessary, as we try to read the dir below.
46- // Such a path does not exist, get out.
39+ for headers_path in [ sys_prefix. join ( "Headers" ) , sys_prefix. join ( "include" ) ] {
40+ if !headers_path. exists ( ) {
4741 continue ;
42+ }
43+ let patchlevel_h = headers_path. join ( "patchlevel.h" ) ;
44+ if let Some ( version) = valid_version_from_header ( & patchlevel_h, pyver) {
45+ return Some ( version) ;
4846 } else {
4947 // Try the other path
5048 // Sometimes we have it in a sub directory such as `python3.10` or `pypy3.9`
@@ -57,18 +55,32 @@ pub fn get_version(path: &Path) -> Option<String> {
5755 }
5856 let path = path. path ( ) ;
5957 let patchlevel_h = path. join ( "patchlevel.h" ) ;
60- if let Ok ( result) = fs:: read_to_string ( patchlevel_h) {
61- contents = result;
62- break ;
58+ if let Some ( version) = valid_version_from_header ( & patchlevel_h, pyver) {
59+ return Some ( version) ;
6360 }
6461 }
6562 }
6663 }
67- for line in contents. lines ( ) {
68- if let Some ( captures) = VERSION . captures ( line) {
69- if let Some ( value) = captures. get ( 1 ) {
70- return Some ( value. as_str ( ) . to_string ( ) ) ;
64+ }
65+ None
66+ }
67+
68+ fn valid_version_from_header ( header : & Path , pyver : Option < ( u64 , u64 ) > ) -> Option < String > {
69+ let contents = fs:: read_to_string ( header) . ok ( ) ?;
70+ for line in contents. lines ( ) {
71+ if let Some ( captures) = VERSION . captures ( line) {
72+ let version = captures. get ( 1 ) ?. as_str ( ) ;
73+ if let Some ( pyver) = pyver {
74+ let parts: Vec < u64 > = version
75+ . splitn ( 3 , "." )
76+ . take ( 2 )
77+ . flat_map ( str:: parse :: < u64 > )
78+ . collect ( ) ;
79+ if parts. len ( ) == 2 && ( parts[ 0 ] , parts[ 1 ] ) == pyver {
80+ return Some ( version. to_string ( ) ) ;
7181 }
82+ } else {
83+ return Some ( version. to_string ( ) ) ;
7284 }
7385 }
7486 }
0 commit comments