]> git.lizzy.rs Git - rust.git/blob - build.rs
Merge pull request #2758 from CAD97/patch-1
[rust.git] / build.rs
1 //! This build script ensures that clippy is not compiled with an
2 //! incompatible version of rust. It will panic with a descriptive
3 //! error message instead.
4 //!
5 //! We specifially want to ensure that clippy is only built with a
6 //! rustc version that is newer or equal to the one specified in the
7 //! `min_version.txt` file.
8 //!
9 //! `min_version.txt` is in the repo but also in the `.gitignore` to
10 //! make sure that it is not updated manually by accident. Only CI
11 //! should update that file.
12 //!
13 //! This build script was originally taken from the Rocket web framework:
14 //! https://github.com/SergioBenitez/Rocket
15
16 extern crate rustc_version;
17 extern crate ansi_term;
18
19 use std::env;
20 use rustc_version::{version_meta, version_meta_for, Channel, Version, VersionMeta};
21 use ansi_term::Colour::Red;
22
23 fn main() {
24     check_rustc_version();
25
26     // Forward the profile to the main compilation
27     println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
28     // Don't rebuild even if nothing changed
29     println!("cargo:rerun-if-changed=build.rs");
30 }
31
32 fn check_rustc_version() {
33     let string = include_str!("min_version.txt");
34     let min_version_meta = version_meta_for(string)
35         .expect("Could not parse version string in min_version.txt");
36     let current_version_meta = version_meta()
37         .expect("Could not retrieve current rustc version information from ENV");
38
39     let min_version = min_version_meta.clone().semver;
40     let min_date_str = min_version_meta.clone().commit_date
41         .expect("min_version.txt does not contain a rustc commit date");
42
43     // Dev channel (rustc built from git) does not have any date or commit information in rustc -vV
44     // `current_version_meta.commit_date` would crash, so we return early here.
45     if current_version_meta.channel == Channel::Dev {
46         return
47     }
48
49     let current_version = current_version_meta.clone().semver;
50     let current_date_str = current_version_meta.clone().commit_date
51         .expect("current rustc version information does not contain a rustc commit date");
52
53     let print_version_err = |version: &Version, date: &str| {
54         eprintln!("> {} {}. {} {}.\n",
55                   "Installed rustc version is:",
56                   format!("{} ({})", version, date),
57                   "Minimum required rustc version:",
58                   format!("{} ({})", min_version, min_date_str));
59     };
60
61     if !correct_channel(&current_version_meta) {
62         eprintln!("\n{} {}",
63                   Red.bold().paint("error:"),
64                   "clippy requires a nightly version of Rust.");
65         print_version_err(&current_version, &*current_date_str);
66         eprintln!("{}{}{}",
67                   "See the README (",
68                   "https://github.com/rust-lang-nursery/rust-clippy#usage",
69                   ") for more information.");
70         panic!("Aborting compilation due to incompatible compiler.")
71     }
72
73     let current_date = str_to_ymd(&current_date_str).unwrap();
74     let min_date = str_to_ymd(&min_date_str).unwrap();
75
76     if current_date < min_date {
77         eprintln!("\n{} {}",
78                   Red.bold().paint("error:"),
79                   "clippy does not support this version of rustc nightly.");
80         eprintln!("> {}{}{}",
81                   "Use `",
82                   "rustup update",
83                   "` or your preferred method to update Rust.");
84         print_version_err(&current_version, &*current_date_str);
85         panic!("Aborting compilation due to incompatible compiler.")
86     }
87 }
88
89 fn correct_channel(version_meta: &VersionMeta) -> bool {
90     match version_meta.channel {
91         Channel::Stable | Channel::Beta => {
92             false
93         },
94         Channel::Nightly | Channel::Dev => {
95             true
96         }
97     }
98 }
99
100 /// Convert a string of %Y-%m-%d to a single u32 maintaining ordering.
101 fn str_to_ymd(ymd: &str) -> Option<u32> {
102     let ymd: Vec<u32> = ymd.split("-").filter_map(|s| s.parse::<u32>().ok()).collect();
103     if ymd.len() != 3 {
104         return None
105     }
106
107     let (y, m, d) = (ymd[0], ymd[1], ymd[2]);
108     Some((y << 9) | (m << 5) | d)
109 }