33 reason = "build scripts cannot use rustpython-host_env"
44) ]
55
6+ use chrono:: { Local , prelude:: DateTime } ;
7+ use core:: time:: Duration ;
68use itertools:: Itertools ;
79use std:: {
810 env,
@@ -24,17 +26,27 @@ fn main() {
2426 }
2527 println ! ( "cargo:rerun-if-changed=../../Lib/importlib/_bootstrap.py" ) ;
2628
29+ // = 3.14.0alpha
30+ python_version ( 3 , 14 , 0 , "alpha" , 0 ) ;
31+
2732 println ! ( "cargo:rustc-env=RUSTPYTHON_GIT_HASH={}" , git_hash( ) ) ;
2833 println ! (
2934 "cargo:rustc-env=RUSTPYTHON_GIT_TIMESTAMP={}" ,
3035 git_timestamp( )
3136 ) ;
3237 println ! ( "cargo:rustc-env=RUSTPYTHON_GIT_TAG={}" , git_tag( ) ) ;
3338 println ! ( "cargo:rustc-env=RUSTPYTHON_GIT_BRANCH={}" , git_branch( ) ) ;
39+ println ! (
40+ "cargo:rustc-env=RUSTPYTHON_GIT_IDENTIFIER={}" ,
41+ git_identifier( )
42+ ) ;
43+ println ! ( "cargo:rustc-env=RUSTPYTHON_BUILD_INFO={}" , get_build_info( ) ) ;
3444 println ! ( "cargo:rustc-env=RUSTC_VERSION={}" , rustc_version( ) ) ;
3545
3646 let release_level = option_env ! ( "RUSTPYTHON_RELEASE_LEVEL" ) . unwrap_or ( "alpha" ) ;
3747 println ! ( "cargo:rustc-env=RUSTPYTHON_RELEASE_LEVEL={release_level}" ) ;
48+ let release_level_n = release_to_n ( release_level) ;
49+ println ! ( "cargo:rustc-env=RUSTPYTHON_RELEASE_LEVEL_N={release_level_n}" ) ;
3850 let release_serial = option_env ! ( "RUSTPYTHON_RELEASE_SERIAL" ) . unwrap_or ( "0" ) ;
3951 println ! ( "cargo:rustc-env=RUSTPYTHON_RELEASE_SERIAL={release_serial}" ) ;
4052
@@ -81,11 +93,127 @@ fn git(args: &[&str]) -> io::Result<String> {
8193 command ( "git" , args)
8294}
8395
96+ #[ must_use]
97+ pub fn get_build_info ( ) -> String {
98+ // See: https://reproducible-builds.org/docs/timestamps/
99+ let revision = git_hash ( ) ;
100+ let separator = if revision. is_empty ( ) { "" } else { ":" } ;
101+ let identifier = git_identifier ( ) ;
102+
103+ format ! (
104+ "{id}{sep}{revision}, {date:.20}, {time:.9}" ,
105+ id = if identifier. is_empty( ) {
106+ "default"
107+ } else {
108+ & identifier
109+ } ,
110+ sep = separator,
111+ revision = revision,
112+ date = get_git_date( ) ,
113+ time = get_git_time( ) ,
114+ )
115+ }
116+
117+ fn git_identifier ( ) -> String {
118+ let tag = git_tag ( ) ;
119+ if tag. is_empty ( ) || tag. eq_ignore_ascii_case ( "undefined" ) {
120+ git_branch ( )
121+ } else {
122+ tag
123+ }
124+ }
125+
126+ fn get_git_timestamp_datetime ( ) -> DateTime < Local > {
127+ let timestamp = git_timestamp ( ) . parse :: < u64 > ( ) . unwrap_or_default ( ) ;
128+ let datetime = UNIX_EPOCH + Duration :: from_secs ( timestamp) ;
129+ datetime. into ( )
130+ }
131+
132+ #[ must_use]
133+ pub fn get_git_date ( ) -> String {
134+ let datetime = get_git_timestamp_datetime ( ) ;
135+
136+ datetime. format ( "%b %e %Y" ) . to_string ( )
137+ }
138+
139+ #[ must_use]
140+ pub fn get_git_time ( ) -> String {
141+ let datetime = get_git_timestamp_datetime ( ) ;
142+
143+ datetime. format ( "%H:%M:%S" ) . to_string ( )
144+ }
145+
146+ #[ must_use]
147+ pub fn get_git_datetime ( ) -> String {
148+ let date = get_git_date ( ) ;
149+ let time = get_git_time ( ) ;
150+
151+ format ! ( "{date} {time}" )
152+ }
153+
84154fn rustc_version ( ) -> String {
85155 let rustc = env:: var_os ( "RUSTC" ) . unwrap_or_else ( || "rustc" . into ( ) ) ;
86156 command ( rustc, & [ "-V" ] ) . unwrap_or_else ( |_| "rustc [unknown]" . into ( ) )
87157}
88158
159+ fn python_version ( major : usize , minor : usize , micro : usize , release : & str , serial : usize ) {
160+ println ! ( "cargo:rustc-env=MAJOR_CPY={major}" ) ;
161+ println ! ( "cargo:rustc-env=MINOR_CPY={minor}" ) ;
162+ println ! ( "cargo:rustc-env=MICRO_CPY={micro}" ) ;
163+ println ! ( "cargo:rustc-env=RELEASE_LEVEL_CPY={release}" ) ;
164+ println ! (
165+ "cargo:rustc-env=RELEASE_LEVEL_N_CPY={}" ,
166+ release_to_n( release)
167+ ) ;
168+ println ! ( "cargo:rustc-env=SERIAL_CPY={serial}" ) ;
169+
170+ println ! ( "cargo:rustc-env=WINVER_CPY={major}.{minor}" , ) ;
171+
172+ let cpy_version = format ! ( "{major}.{minor}.{micro}.{release}" ) ;
173+
174+ let ( left, right) = get_version ( & cpy_version) ;
175+ println ! ( "cargo:rustc-env=RUSTPYTHON_VERSION_LEFT={left}" ) ;
176+ println ! ( "cargo:rustc-env=RUSTPYTHON_VERSION_RIGHT={right}" ) ;
177+ }
178+
179+ #[ must_use]
180+ pub fn get_version ( cpy_version : & str ) -> ( String , String ) {
181+ // Windows: include MSC v. for compatibility with ctypes.util.find_library
182+ // MSC v.1929 = VS 2019, version 14+ makes find_msvcrt() return None
183+ let msc_info = cfg_select ! {
184+ windows => { {
185+ // Include both RustPython identifier and MSC v. for compatibility
186+ if cfg!( target_pointer_width = "64" ) {
187+ " MSC v.1929 64 bit (AMD64)"
188+ } else {
189+ " MSC v.1929 32 bit (Intel)"
190+ }
191+ } } ,
192+ _ => "" ,
193+ } ;
194+
195+ // `left` and `right` are split by \n like PyPy. Passing a string with a newline to rustc
196+ // truncates everything from the newline onward, so we have to manually combine them later.
197+ let left = format ! ( "{:.80} ({:.80})" , cpy_version, get_build_info( ) ) ;
198+ let right = format ! (
199+ "[RustPython {} with {:.80}{}]" ,
200+ env!( "CARGO_PKG_VERSION" ) ,
201+ rustc_version( ) ,
202+ msc_info,
203+ ) ;
204+ ( left, right)
205+ }
206+
207+ fn release_to_n ( release : & str ) -> usize {
208+ match release {
209+ "alpha" => 0xA ,
210+ "beta" => 0xB ,
211+ "candidate" => 0xC ,
212+ "final" => 0xD ,
213+ _ => unreachable ! ( ) ,
214+ }
215+ }
216+
89217fn command ( cmd : impl AsRef < std:: ffi:: OsStr > , args : & [ & str ] ) -> io:: Result < String > {
90218 Command :: new ( & cmd) . args ( args) . output ( ) . and_then ( |output| {
91219 // TODO: Switch to exit_ok()? when stable.
0 commit comments