aboutsummaryrefslogtreecommitdiff
path: root/xtask/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'xtask/src/main.rs')
-rw-r--r--xtask/src/main.rs273
1 files changed, 148 insertions, 125 deletions
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index cbb9b315e..e419db7a7 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -7,59 +7,44 @@
7//! 7//!
8//! This binary is integrated into the `cargo` command line by using an alias in 8//! This binary is integrated into the `cargo` command line by using an alias in
9//! `.cargo/config`. 9//! `.cargo/config`.
10mod flags;
10 11
11use std::env; 12mod codegen;
13mod ast_src;
14#[cfg(test)]
15mod tidy;
12 16
13use anyhow::bail; 17mod install;
14use codegen::CodegenCmd; 18mod release;
15use pico_args::Arguments; 19mod dist;
16use xshell::{cmd, cp, pushd}; 20mod metrics;
17use xtask::{ 21mod pre_cache;
18 codegen::{self, Mode}, 22
23use anyhow::{bail, Result};
24use std::{
25 env,
26 path::{Path, PathBuf},
27};
28use walkdir::{DirEntry, WalkDir};
29use xshell::{cmd, cp, pushd, pushenv};
30
31use crate::{
32 codegen::Mode,
19 dist::DistCmd, 33 dist::DistCmd,
20 install::{InstallCmd, Malloc, ServerOpt}, 34 install::{InstallCmd, Malloc, ServerOpt},
21 metrics::MetricsCmd,
22 pre_cache::PreCacheCmd,
23 pre_commit, project_root,
24 release::{PromoteCmd, ReleaseCmd},
25 run_clippy, run_fuzzer, run_rustfmt, Result,
26}; 35};
27 36
28fn main() -> Result<()> { 37fn main() -> Result<()> {
29 if env::args().next().map(|it| it.contains("pre-commit")) == Some(true) {
30 return pre_commit::run_hook();
31 }
32
33 let _d = pushd(project_root())?; 38 let _d = pushd(project_root())?;
34 39
35 let mut args = Arguments::from_env(); 40 let flags = flags::Xtask::from_env()?;
36 let subcommand = args.subcommand()?.unwrap_or_default(); 41 match flags.subcommand {
37 42 flags::XtaskCmd::Help(_) => {
38 match subcommand.as_str() { 43 println!("{}", flags::Xtask::HELP);
39 "install" => { 44 return Ok(());
40 if args.contains(["-h", "--help"]) { 45 }
41 eprintln!( 46 flags::XtaskCmd::Install(flags) => {
42 "\ 47 if flags.server && flags.client {
43cargo xtask install
44Install rust-analyzer server or editor plugin.
45
46USAGE:
47 cargo xtask install [FLAGS]
48
49FLAGS:
50 --client[=CLIENT] Install only VS Code plugin.
51 CLIENT is one of 'code', 'code-exploration', 'code-insiders', 'codium', or 'code-oss'
52 --server Install only the language server
53 --mimalloc Use mimalloc allocator for server
54 --jemalloc Use jemalloc allocator for server
55 -h, --help Prints help information
56 "
57 );
58 return Ok(());
59 }
60 let server = args.contains("--server");
61 let client_code = args.contains("--client");
62 if server && client_code {
63 eprintln!( 48 eprintln!(
64 "error: The argument `--server` cannot be used with `--client`\n\n\ 49 "error: The argument `--server` cannot be used with `--client`\n\n\
65 For more information try --help" 50 For more information try --help"
@@ -67,108 +52,146 @@ FLAGS:
67 return Ok(()); 52 return Ok(());
68 } 53 }
69 54
70 let malloc = if args.contains("--mimalloc") { 55 let malloc = if flags.mimalloc {
71 Malloc::Mimalloc 56 Malloc::Mimalloc
72 } else if args.contains("--jemalloc") { 57 } else if flags.jemalloc {
73 Malloc::Jemalloc 58 Malloc::Jemalloc
74 } else { 59 } else {
75 Malloc::System 60 Malloc::System
76 }; 61 };
77 62
78 let client_opt = args.opt_value_from_str("--client")?; 63 let client_bin = flags.code_bin.map(|it| it.parse()).transpose()?;
79
80 finish_args(args)?;
81 64
82 InstallCmd { 65 InstallCmd {
83 client: if server { None } else { Some(client_opt.unwrap_or_default()) }, 66 client: if flags.server { None } else { client_bin },
84 server: if client_code { None } else { Some(ServerOpt { malloc }) }, 67 server: if flags.client { None } else { Some(ServerOpt { malloc }) },
85 } 68 }
86 .run() 69 .run()
87 } 70 }
88 "codegen" => { 71 flags::XtaskCmd::Codegen(cmd) => cmd.run(),
89 let features = args.contains("--features"); 72 flags::XtaskCmd::Lint(_) => run_clippy(),
90 finish_args(args)?; 73 flags::XtaskCmd::FuzzTests(_) => run_fuzzer(),
91 CodegenCmd { features }.run() 74 flags::XtaskCmd::PreCache(cmd) => cmd.run(),
92 } 75 flags::XtaskCmd::Release(cmd) => cmd.run(),
93 "format" => { 76 flags::XtaskCmd::Promote(cmd) => cmd.run(),
94 finish_args(args)?; 77 flags::XtaskCmd::Dist(flags) => {
95 run_rustfmt(Mode::Overwrite) 78 DistCmd { nightly: flags.nightly, client_version: flags.client }.run()
96 }
97 "install-pre-commit-hook" => {
98 finish_args(args)?;
99 pre_commit::install_hook()
100 } 79 }
101 "lint" => { 80 flags::XtaskCmd::Metrics(cmd) => cmd.run(),
102 finish_args(args)?; 81 flags::XtaskCmd::Bb(cmd) => {
103 run_clippy()
104 }
105 "fuzz-tests" => {
106 finish_args(args)?;
107 run_fuzzer()
108 }
109 "pre-cache" => {
110 finish_args(args)?;
111 PreCacheCmd.run()
112 }
113 "release" => {
114 let dry_run = args.contains("--dry-run");
115 finish_args(args)?;
116 ReleaseCmd { dry_run }.run()
117 }
118 "promote" => {
119 let dry_run = args.contains("--dry-run");
120 finish_args(args)?;
121 PromoteCmd { dry_run }.run()
122 }
123 "dist" => {
124 let nightly = args.contains("--nightly");
125 let client_version: Option<String> = args.opt_value_from_str("--client")?;
126 finish_args(args)?;
127 DistCmd { nightly, client_version }.run()
128 }
129 "metrics" => {
130 let dry_run = args.contains("--dry-run");
131 finish_args(args)?;
132 MetricsCmd { dry_run }.run()
133 }
134 "bb" => {
135 let suffix: String = args.free_from_str()?;
136 finish_args(args)?;
137 { 82 {
138 let _d = pushd("./crates/rust-analyzer")?; 83 let _d = pushd("./crates/rust-analyzer")?;
139 cmd!("cargo build --release --features jemalloc").run()?; 84 cmd!("cargo build --release --features jemalloc").run()?;
140 } 85 }
141 cp("./target/release/rust-analyzer", format!("./target/rust-analyzer-{}", suffix))?; 86 cp("./target/release/rust-analyzer", format!("./target/rust-analyzer-{}", cmd.suffix))?;
142 Ok(())
143 }
144 _ => {
145 eprintln!(
146 "\
147cargo xtask
148Run custom build command.
149
150USAGE:
151 cargo xtask <SUBCOMMAND>
152
153SUBCOMMANDS:
154 format
155 install-pre-commit-hook
156 fuzz-tests
157 codegen
158 install
159 lint
160 dist
161 promote
162 bb"
163 );
164 Ok(()) 87 Ok(())
165 } 88 }
166 } 89 }
167} 90}
168 91
169fn finish_args(args: Arguments) -> Result<()> { 92fn project_root() -> PathBuf {
170 if !args.finish().is_empty() { 93 Path::new(
171 bail!("Unused arguments."); 94 &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
95 )
96 .ancestors()
97 .nth(1)
98 .unwrap()
99 .to_path_buf()
100}
101
102fn rust_files() -> impl Iterator<Item = PathBuf> {
103 rust_files_in(&project_root().join("crates"))
104}
105
106#[cfg(test)]
107fn cargo_files() -> impl Iterator<Item = PathBuf> {
108 files_in(&project_root(), "toml")
109 .filter(|path| path.file_name().map(|it| it == "Cargo.toml").unwrap_or(false))
110}
111
112fn rust_files_in(path: &Path) -> impl Iterator<Item = PathBuf> {
113 files_in(path, "rs")
114}
115
116fn run_rustfmt(mode: Mode) -> Result<()> {
117 let _dir = pushd(project_root())?;
118 let _e = pushenv("RUSTUP_TOOLCHAIN", "stable");
119 ensure_rustfmt()?;
120 let check = match mode {
121 Mode::Overwrite => &[][..],
122 Mode::Verify => &["--", "--check"],
123 };
124 cmd!("cargo fmt {check...}").run()?;
125 Ok(())
126}
127
128fn ensure_rustfmt() -> Result<()> {
129 let out = cmd!("rustfmt --version").read()?;
130 if !out.contains("stable") {
131 bail!(
132 "Failed to run rustfmt from toolchain 'stable'. \
133 Please run `rustup component add rustfmt --toolchain stable` to install it.",
134 )
135 }
136 Ok(())
137}
138
139fn run_clippy() -> Result<()> {
140 if cmd!("cargo clippy --version").read().is_err() {
141 bail!(
142 "Failed run cargo clippy. \
143 Please run `rustup component add clippy` to install it.",
144 )
145 }
146
147 let allowed_lints = "
148 -A clippy::collapsible_if
149 -A clippy::needless_pass_by_value
150 -A clippy::nonminimal_bool
151 -A clippy::redundant_pattern_matching
152 "
153 .split_ascii_whitespace();
154 cmd!("cargo clippy --all-features --all-targets -- {allowed_lints...}").run()?;
155 Ok(())
156}
157
158fn run_fuzzer() -> Result<()> {
159 let _d = pushd("./crates/syntax")?;
160 let _e = pushenv("RUSTUP_TOOLCHAIN", "nightly");
161 if cmd!("cargo fuzz --help").read().is_err() {
162 cmd!("cargo install cargo-fuzz").run()?;
163 };
164
165 // Expecting nightly rustc
166 let out = cmd!("rustc --version").read()?;
167 if !out.contains("nightly") {
168 bail!("fuzz tests require nightly rustc")
172 } 169 }
170
171 cmd!("cargo fuzz run parser").run()?;
173 Ok(()) 172 Ok(())
174} 173}
174
175fn date_iso() -> Result<String> {
176 let res = cmd!("date --iso --utc").read()?;
177 Ok(res)
178}
179
180fn is_release_tag(tag: &str) -> bool {
181 tag.len() == "2020-02-24".len() && tag.starts_with(|c: char| c.is_ascii_digit())
182}
183
184fn files_in(path: &Path, ext: &'static str) -> impl Iterator<Item = PathBuf> {
185 let iter = WalkDir::new(path);
186 return iter
187 .into_iter()
188 .filter_entry(|e| !is_hidden(e))
189 .map(|e| e.unwrap())
190 .filter(|e| !e.file_type().is_dir())
191 .map(|e| e.into_path())
192 .filter(move |path| path.extension().map(|it| it == ext).unwrap_or(false));
193
194 fn is_hidden(entry: &DirEntry) -> bool {
195 entry.file_name().to_str().map(|s| s.starts_with('.')).unwrap_or(false)
196 }
197}