Skip to main content

rustpython_vm/
version.rs

1//! Several function to retrieve version information.
2
3use chrono::{Local, prelude::DateTime};
4use core::time::Duration;
5use std::time::UNIX_EPOCH;
6
7// = 3.14.0alpha
8pub const MAJOR: usize = 3;
9pub const MINOR: usize = 14;
10pub const MICRO: usize = 0;
11pub const RELEASELEVEL: &str = "alpha";
12pub const RELEASELEVEL_N: usize = 0xA;
13pub const SERIAL: usize = 0;
14
15pub const VERSION_HEX: usize =
16    (MAJOR << 24) | (MINOR << 16) | (MICRO << 8) | (RELEASELEVEL_N << 4) | SERIAL;
17
18pub fn get_version() -> String {
19    // Windows: include MSC v. for compatibility with ctypes.util.find_library
20    // MSC v.1929 = VS 2019, version 14+ makes find_msvcrt() return None
21    #[cfg(windows)]
22    let msc_info = {
23        let arch = if cfg!(target_pointer_width = "64") {
24            "64 bit (AMD64)"
25        } else {
26            "32 bit (Intel)"
27        };
28        // Include both RustPython identifier and MSC v. for compatibility
29        format!(" MSC v.1929 {arch}",)
30    };
31
32    #[cfg(not(windows))]
33    let msc_info = String::new();
34
35    format!(
36        "{:.80} ({:.80}) \n[RustPython {} with {:.80}{}]", // \n is PyPy convention
37        get_version_number(),
38        get_build_info(),
39        env!("CARGO_PKG_VERSION"),
40        COMPILER,
41        msc_info,
42    )
43}
44
45pub fn get_version_number() -> String {
46    format!("{MAJOR}.{MINOR}.{MICRO}{RELEASELEVEL}")
47}
48
49pub fn get_winver_number() -> String {
50    format!("{MAJOR}.{MINOR}")
51}
52
53const COMPILER: &str = env!("RUSTC_VERSION");
54
55pub fn get_build_info() -> String {
56    // See: https://reproducible-builds.org/docs/timestamps/
57    let git_revision = get_git_revision();
58    let separator = if git_revision.is_empty() { "" } else { ":" };
59
60    let git_identifier = get_git_identifier();
61
62    format!(
63        "{id}{sep}{revision}, {date:.20}, {time:.9}",
64        id = if git_identifier.is_empty() {
65            "default".to_owned()
66        } else {
67            git_identifier
68        },
69        sep = separator,
70        revision = git_revision,
71        date = get_git_date(),
72        time = get_git_time(),
73    )
74}
75
76pub fn get_git_revision() -> String {
77    option_env!("RUSTPYTHON_GIT_HASH").unwrap_or("").to_owned()
78}
79
80pub fn get_git_tag() -> String {
81    option_env!("RUSTPYTHON_GIT_TAG").unwrap_or("").to_owned()
82}
83
84pub fn get_git_branch() -> String {
85    option_env!("RUSTPYTHON_GIT_BRANCH")
86        .unwrap_or("")
87        .to_owned()
88}
89
90pub fn get_git_identifier() -> String {
91    let git_tag = get_git_tag();
92    let git_branch = get_git_branch();
93
94    if git_tag.is_empty() || git_tag == "undefined" {
95        git_branch
96    } else {
97        git_tag
98    }
99}
100
101fn get_git_timestamp_datetime() -> DateTime<Local> {
102    let timestamp = option_env!("RUSTPYTHON_GIT_TIMESTAMP")
103        .unwrap_or("")
104        .to_owned();
105    let timestamp = timestamp.parse::<u64>().unwrap_or(0);
106
107    let datetime = UNIX_EPOCH + Duration::from_secs(timestamp);
108
109    datetime.into()
110}
111
112pub fn get_git_date() -> String {
113    let datetime = get_git_timestamp_datetime();
114
115    datetime.format("%b %e %Y").to_string()
116}
117
118pub fn get_git_time() -> String {
119    let datetime = get_git_timestamp_datetime();
120
121    datetime.format("%H:%M:%S").to_string()
122}
123
124pub fn get_git_datetime() -> String {
125    let date = get_git_date();
126    let time = get_git_time();
127
128    format!("{date} {time}")
129}
130
131// Must be aligned to Lib/importlib/_bootstrap_external.py
132// Bumped to 2994 for new CommonConstant discriminants (BuiltinList, BuiltinSet)
133pub const PYC_MAGIC_NUMBER: u16 = 2994;
134
135// CPython format: magic_number | ('\r' << 16) | ('\n' << 24)
136// This protects against text-mode file reads
137pub const PYC_MAGIC_NUMBER_TOKEN: u32 =
138    (PYC_MAGIC_NUMBER as u32) | ((b'\r' as u32) << 16) | ((b'\n' as u32) << 24);
139
140/// Magic number as little-endian bytes for .pyc files
141pub const PYC_MAGIC_NUMBER_BYTES: [u8; 4] = PYC_MAGIC_NUMBER_TOKEN.to_le_bytes();