summaryrefslogtreecommitdiffstats
path: root/third_party/rust/rustc_version/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/rustc_version/src
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/rustc_version/src')
-rw-r--r--third_party/rust/rustc_version/src/lib.rs417
1 files changed, 417 insertions, 0 deletions
diff --git a/third_party/rust/rustc_version/src/lib.rs b/third_party/rust/rustc_version/src/lib.rs
new file mode 100644
index 0000000000..cee1ec8143
--- /dev/null
+++ b/third_party/rust/rustc_version/src/lib.rs
@@ -0,0 +1,417 @@
+// Copyright 2016 rustc-version-rs developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![warn(missing_docs)]
+
+//! Simple library for getting the version information of a `rustc`
+//! compiler.
+//!
+//! This can be used by build scripts or other tools dealing with Rust sources
+//! to make decisions based on the version of the compiler.
+//!
+//! It calls `$RUSTC --version -v` and parses the output, falling
+//! back to `rustc` if `$RUSTC` is not set.
+//!
+//! # Example
+//!
+//! ```rust
+//! // This could be a cargo build script
+//!
+//! use rustc_version::{version, version_meta, Channel, Version};
+//!
+//! // Assert we haven't travelled back in time
+//! assert!(version().unwrap().major >= 1);
+//!
+//! // Set cfg flags depending on release channel
+//! match version_meta().unwrap().channel {
+//! Channel::Stable => {
+//! println!("cargo:rustc-cfg=RUSTC_IS_STABLE");
+//! }
+//! Channel::Beta => {
+//! println!("cargo:rustc-cfg=RUSTC_IS_BETA");
+//! }
+//! Channel::Nightly => {
+//! println!("cargo:rustc-cfg=RUSTC_IS_NIGHTLY");
+//! }
+//! Channel::Dev => {
+//! println!("cargo:rustc-cfg=RUSTC_IS_DEV");
+//! }
+//! }
+//!
+//! // Check for a minimum version
+//! if version().unwrap() >= Version::parse("1.4.0").unwrap() {
+//! println!("cargo:rustc-cfg=compiler_has_important_bugfix");
+//! }
+//! ```
+
+#[cfg(test)]
+#[macro_use]
+extern crate doc_comment;
+
+#[cfg(test)]
+doctest!("../README.md");
+
+use std::collections::HashMap;
+use std::process::Command;
+use std::{env, error, fmt, io, num, str};
+use std::{ffi::OsString, str::FromStr};
+
+// Convenience re-export to allow version comparison without needing to add
+// semver crate.
+pub use semver::Version;
+
+use Error::*;
+
+/// Release channel of the compiler.
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
+pub enum Channel {
+ /// Development release channel
+ Dev,
+ /// Nightly release channel
+ Nightly,
+ /// Beta release channel
+ Beta,
+ /// Stable release channel
+ Stable,
+}
+
+/// LLVM version
+///
+/// LLVM's version numbering scheme is not semver compatible until version 4.0
+///
+/// rustc [just prints the major and minor versions], so other parts of the version are not included.
+///
+/// [just prints the major and minor versions]: https://github.com/rust-lang/rust/blob/b5c9e2448c9ace53ad5c11585803894651b18b0a/compiler/rustc_codegen_llvm/src/llvm_util.rs#L173-L178
+#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub struct LlvmVersion {
+ // fields must be ordered major, minor for comparison to be correct
+ /// Major version
+ pub major: u64,
+ /// Minor version
+ pub minor: u64,
+ // TODO: expose micro version here
+}
+
+impl fmt::Display for LlvmVersion {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}.{}", self.major, self.minor)
+ }
+}
+
+impl FromStr for LlvmVersion {
+ type Err = LlvmVersionParseError;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ let mut parts = s
+ .split('.')
+ .map(|part| -> Result<u64, LlvmVersionParseError> {
+ if part == "0" {
+ Ok(0)
+ } else if part.starts_with('0') {
+ Err(LlvmVersionParseError::ComponentMustNotHaveLeadingZeros)
+ } else if part.starts_with('-') || part.starts_with('+') {
+ Err(LlvmVersionParseError::ComponentMustNotHaveSign)
+ } else {
+ Ok(part.parse()?)
+ }
+ });
+
+ let major = parts.next().unwrap()?;
+ let mut minor = 0;
+
+ if let Some(part) = parts.next() {
+ minor = part?;
+ } else if major < 4 {
+ // LLVM versions earlier than 4.0 have significant minor versions, so require the minor version in this case.
+ return Err(LlvmVersionParseError::MinorVersionRequiredBefore4);
+ }
+
+ if let Some(Err(e)) = parts.next() {
+ return Err(e);
+ }
+
+ if parts.next().is_some() {
+ return Err(LlvmVersionParseError::TooManyComponents);
+ }
+
+ Ok(Self { major, minor })
+ }
+}
+
+/// Rustc version plus metadata like git short hash and build date.
+#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub struct VersionMeta {
+ /// Version of the compiler
+ pub semver: Version,
+
+ /// Git short hash of the build of the compiler
+ pub commit_hash: Option<String>,
+
+ /// Commit date of the compiler
+ pub commit_date: Option<String>,
+
+ /// Build date of the compiler; this was removed between Rust 1.0.0 and 1.1.0.
+ pub build_date: Option<String>,
+
+ /// Release channel of the compiler
+ pub channel: Channel,
+
+ /// Host target triple of the compiler
+ pub host: String,
+
+ /// Short version string of the compiler
+ pub short_version_string: String,
+
+ /// Version of LLVM used by the compiler
+ pub llvm_version: Option<LlvmVersion>,
+}
+
+impl VersionMeta {
+ /// Returns the version metadata for `cmd`, which should be a `rustc` command.
+ pub fn for_command(mut cmd: Command) -> Result<VersionMeta> {
+ let out = cmd
+ .arg("-vV")
+ .output()
+ .map_err(Error::CouldNotExecuteCommand)?;
+
+ if !out.status.success() {
+ return Err(Error::CommandError {
+ stdout: String::from_utf8_lossy(&out.stdout).into(),
+ stderr: String::from_utf8_lossy(&out.stderr).into(),
+ });
+ }
+
+ version_meta_for(str::from_utf8(&out.stdout)?)
+ }
+}
+
+/// Returns the `rustc` SemVer version.
+pub fn version() -> Result<Version> {
+ Ok(version_meta()?.semver)
+}
+
+/// Returns the `rustc` SemVer version and additional metadata
+/// like the git short hash and build date.
+pub fn version_meta() -> Result<VersionMeta> {
+ let cmd = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
+
+ VersionMeta::for_command(Command::new(cmd))
+}
+
+/// Parses a "rustc -vV" output string and returns
+/// the SemVer version and additional metadata
+/// like the git short hash and build date.
+pub fn version_meta_for(verbose_version_string: &str) -> Result<VersionMeta> {
+ let mut map = HashMap::new();
+ for (i, line) in verbose_version_string.lines().enumerate() {
+ if i == 0 {
+ map.insert("short", line);
+ continue;
+ }
+
+ let mut parts = line.splitn(2, ": ");
+ let key = match parts.next() {
+ Some(key) => key,
+ None => continue,
+ };
+
+ if let Some(value) = parts.next() {
+ map.insert(key, value);
+ }
+ }
+
+ let short_version_string = expect_key("short", &map)?;
+ let host = expect_key("host", &map)?;
+ let release = expect_key("release", &map)?;
+ let semver: Version = release.parse()?;
+
+ let channel = match semver.pre.split('.').next().unwrap() {
+ "" => Channel::Stable,
+ "dev" => Channel::Dev,
+ "beta" => Channel::Beta,
+ "nightly" => Channel::Nightly,
+ x => return Err(Error::UnknownPreReleaseTag(x.to_owned())),
+ };
+
+ let commit_hash = expect_key_or_unknown("commit-hash", &map)?;
+ let commit_date = expect_key_or_unknown("commit-date", &map)?;
+ let build_date = map
+ .get("build-date")
+ .filter(|&v| *v != "unknown")
+ .map(|&v| String::from(v));
+ let llvm_version = match map.get("LLVM version") {
+ Some(&v) => Some(v.parse()?),
+ None => None,
+ };
+
+ Ok(VersionMeta {
+ semver,
+ commit_hash,
+ commit_date,
+ build_date,
+ channel,
+ host,
+ short_version_string,
+ llvm_version,
+ })
+}
+
+fn expect_key_or_unknown(key: &str, map: &HashMap<&str, &str>) -> Result<Option<String>, Error> {
+ match map.get(key) {
+ Some(&v) if v == "unknown" => Ok(None),
+ Some(&v) => Ok(Some(String::from(v))),
+ None => Err(Error::UnexpectedVersionFormat),
+ }
+}
+
+fn expect_key(key: &str, map: &HashMap<&str, &str>) -> Result<String, Error> {
+ map.get(key)
+ .map(|&v| String::from(v))
+ .ok_or(Error::UnexpectedVersionFormat)
+}
+
+/// LLVM Version Parse Error
+#[derive(Debug)]
+pub enum LlvmVersionParseError {
+ /// An error occurred in parsing a version component as an integer
+ ParseIntError(num::ParseIntError),
+ /// A version component must not have leading zeros
+ ComponentMustNotHaveLeadingZeros,
+ /// A version component has a sign
+ ComponentMustNotHaveSign,
+ /// Minor version component must be zero on LLVM versions later than 4.0
+ MinorVersionMustBeZeroAfter4,
+ /// Minor version component is required on LLVM versions earlier than 4.0
+ MinorVersionRequiredBefore4,
+ /// Too many components
+ TooManyComponents,
+}
+
+impl From<num::ParseIntError> for LlvmVersionParseError {
+ fn from(e: num::ParseIntError) -> Self {
+ LlvmVersionParseError::ParseIntError(e)
+ }
+}
+
+impl fmt::Display for LlvmVersionParseError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ LlvmVersionParseError::ParseIntError(e) => {
+ write!(f, "error parsing LLVM version component: {}", e)
+ }
+ LlvmVersionParseError::ComponentMustNotHaveLeadingZeros => {
+ write!(f, "a version component must not have leading zeros")
+ }
+ LlvmVersionParseError::ComponentMustNotHaveSign => {
+ write!(f, "a version component must not have a sign")
+ }
+ LlvmVersionParseError::MinorVersionMustBeZeroAfter4 => write!(
+ f,
+ "LLVM's minor version component must be 0 for versions greater than 4.0"
+ ),
+ LlvmVersionParseError::MinorVersionRequiredBefore4 => write!(
+ f,
+ "LLVM's minor version component is required for versions less than 4.0"
+ ),
+ LlvmVersionParseError::TooManyComponents => write!(f, "too many version components"),
+ }
+ }
+}
+
+impl error::Error for LlvmVersionParseError {
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match self {
+ LlvmVersionParseError::ParseIntError(e) => Some(e),
+ LlvmVersionParseError::ComponentMustNotHaveLeadingZeros
+ | LlvmVersionParseError::ComponentMustNotHaveSign
+ | LlvmVersionParseError::MinorVersionMustBeZeroAfter4
+ | LlvmVersionParseError::MinorVersionRequiredBefore4
+ | LlvmVersionParseError::TooManyComponents => None,
+ }
+ }
+}
+
+/// The error type for this crate.
+#[derive(Debug)]
+pub enum Error {
+ /// An error occurred while trying to find the `rustc` to run.
+ CouldNotExecuteCommand(io::Error),
+ /// Error output from the command that was run.
+ CommandError {
+ /// stdout output from the command
+ stdout: String,
+ /// stderr output from the command
+ stderr: String,
+ },
+ /// The output of `rustc -vV` was not valid utf-8.
+ Utf8Error(str::Utf8Error),
+ /// The output of `rustc -vV` was not in the expected format.
+ UnexpectedVersionFormat,
+ /// An error occurred in parsing the semver.
+ SemVerError(semver::Error),
+ /// The pre-release tag is unknown.
+ UnknownPreReleaseTag(String),
+ /// An error occurred in parsing a `LlvmVersion`.
+ LlvmVersionError(LlvmVersionParseError),
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ CouldNotExecuteCommand(ref e) => write!(f, "could not execute command: {}", e),
+ CommandError {
+ ref stdout,
+ ref stderr,
+ } => write!(
+ f,
+ "error from command -- stderr:\n\n{}\n\nstderr:\n\n{}",
+ stderr, stdout,
+ ),
+ Utf8Error(_) => write!(f, "invalid UTF-8 output from `rustc -vV`"),
+ UnexpectedVersionFormat => write!(f, "unexpected `rustc -vV` format"),
+ SemVerError(ref e) => write!(f, "error parsing version: {}", e),
+ UnknownPreReleaseTag(ref i) => write!(f, "unknown pre-release tag: {}", i),
+ LlvmVersionError(ref e) => write!(f, "error parsing LLVM's version: {}", e),
+ }
+ }
+}
+
+impl error::Error for Error {
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ CouldNotExecuteCommand(ref e) => Some(e),
+ CommandError { .. } => None,
+ Utf8Error(ref e) => Some(e),
+ UnexpectedVersionFormat => None,
+ SemVerError(ref e) => Some(e),
+ UnknownPreReleaseTag(_) => None,
+ LlvmVersionError(ref e) => Some(e),
+ }
+ }
+}
+
+macro_rules! impl_from {
+ ($($err_ty:ty => $variant:ident),* $(,)*) => {
+ $(
+ impl From<$err_ty> for Error {
+ fn from(e: $err_ty) -> Error {
+ Error::$variant(e)
+ }
+ }
+ )*
+ }
+}
+
+impl_from! {
+ str::Utf8Error => Utf8Error,
+ semver::Error => SemVerError,
+ LlvmVersionParseError => LlvmVersionError,
+}
+
+/// The result type for this crate.
+pub type Result<T, E = Error> = std::result::Result<T, E>;