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.rs274
1 files changed, 128 insertions, 146 deletions
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index cbb9b315e..057cd57ae 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -1,174 +1,156 @@
1//! See https://github.com/matklad/cargo-xtask/. 1//! See https://github.com/matklad/cargo-xtask/.
2//! 2//!
3//! This binary defines various auxiliary build commands, which are not 3//! This binary defines various auxiliary build commands, which are not
4//! expressible with just `cargo`. Notably, it provides `cargo xtask codegen` 4//! expressible with just `cargo`. Notably, it provides tests via `cargo test -p xtask`
5//! for code generation and `cargo xtask install` for installation of 5//! for code generation and `cargo xtask install` for installation of
6//! rust-analyzer server and client. 6//! rust-analyzer server and client.
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;
12 13mod ast_src;
13use anyhow::bail; 14#[cfg(test)]
14use codegen::CodegenCmd; 15mod tidy;
15use pico_args::Arguments;
16use xshell::{cmd, cp, pushd};
17use xtask::{
18 codegen::{self, Mode},
19 dist::DistCmd,
20 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};
27 16
28fn main() -> Result<()> { 17mod install;
29 if env::args().next().map(|it| it.contains("pre-commit")) == Some(true) { 18mod release;
30 return pre_commit::run_hook(); 19mod dist;
31 } 20mod metrics;
21mod pre_cache;
32 22
33 let _d = pushd(project_root())?; 23use anyhow::{bail, Result};
34 24use std::{
35 let mut args = Arguments::from_env(); 25 env,
36 let subcommand = args.subcommand()?.unwrap_or_default(); 26 path::{Path, PathBuf},
37 27};
38 match subcommand.as_str() { 28use walkdir::{DirEntry, WalkDir};
39 "install" => { 29use xshell::{cmd, cp, pushd, pushenv};
40 if args.contains(["-h", "--help"]) {
41 eprintln!(
42 "\
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!(
64 "error: The argument `--server` cannot be used with `--client`\n\n\
65 For more information try --help"
66 );
67 return Ok(());
68 }
69
70 let malloc = if args.contains("--mimalloc") {
71 Malloc::Mimalloc
72 } else if args.contains("--jemalloc") {
73 Malloc::Jemalloc
74 } else {
75 Malloc::System
76 };
77 30
78 let client_opt = args.opt_value_from_str("--client")?; 31use crate::dist::DistCmd;
79 32
80 finish_args(args)?; 33fn main() -> Result<()> {
34 let _d = pushd(project_root())?;
81 35
82 InstallCmd { 36 let flags = flags::Xtask::from_env()?;
83 client: if server { None } else { Some(client_opt.unwrap_or_default()) }, 37 match flags.subcommand {
84 server: if client_code { None } else { Some(ServerOpt { malloc }) }, 38 flags::XtaskCmd::Help(_) => {
85 } 39 println!("{}", flags::Xtask::HELP);
86 .run() 40 return Ok(());
87 }
88 "codegen" => {
89 let features = args.contains("--features");
90 finish_args(args)?;
91 CodegenCmd { features }.run()
92 } 41 }
93 "format" => { 42 flags::XtaskCmd::Install(cmd) => cmd.run(),
94 finish_args(args)?; 43 flags::XtaskCmd::Lint(_) => run_clippy(),
95 run_rustfmt(Mode::Overwrite) 44 flags::XtaskCmd::FuzzTests(_) => run_fuzzer(),
45 flags::XtaskCmd::PreCache(cmd) => cmd.run(),
46 flags::XtaskCmd::Release(cmd) => cmd.run(),
47 flags::XtaskCmd::Promote(cmd) => cmd.run(),
48 flags::XtaskCmd::Dist(flags) => {
49 DistCmd { nightly: flags.nightly, client_version: flags.client }.run()
96 } 50 }
97 "install-pre-commit-hook" => { 51 flags::XtaskCmd::Metrics(cmd) => cmd.run(),
98 finish_args(args)?; 52 flags::XtaskCmd::Bb(cmd) => {
99 pre_commit::install_hook()
100 }
101 "lint" => {
102 finish_args(args)?;
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 { 53 {
138 let _d = pushd("./crates/rust-analyzer")?; 54 let _d = pushd("./crates/rust-analyzer")?;
139 cmd!("cargo build --release --features jemalloc").run()?; 55 cmd!("cargo build --release --features jemalloc").run()?;
140 } 56 }
141 cp("./target/release/rust-analyzer", format!("./target/rust-analyzer-{}", suffix))?; 57 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(()) 58 Ok(())
165 } 59 }
166 } 60 }
167} 61}
168 62
169fn finish_args(args: Arguments) -> Result<()> { 63fn project_root() -> PathBuf {
170 if !args.finish().is_empty() { 64 Path::new(
171 bail!("Unused arguments."); 65 &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
66 )
67 .ancestors()
68 .nth(1)
69 .unwrap()
70 .to_path_buf()
71}
72
73fn rust_files() -> impl Iterator<Item = PathBuf> {
74 rust_files_in(&project_root().join("crates"))
75}
76
77#[cfg(test)]
78fn cargo_files() -> impl Iterator<Item = PathBuf> {
79 files_in(&project_root(), "toml")
80 .filter(|path| path.file_name().map(|it| it == "Cargo.toml").unwrap_or(false))
81}
82
83fn rust_files_in(path: &Path) -> impl Iterator<Item = PathBuf> {
84 files_in(path, "rs")
85}
86
87fn ensure_rustfmt() -> Result<()> {
88 let out = cmd!("rustfmt --version").read()?;
89 if !out.contains("stable") {
90 bail!(
91 "Failed to run rustfmt from toolchain 'stable'. \
92 Please run `rustup component add rustfmt --toolchain stable` to install it.",
93 )
94 }
95 Ok(())
96}
97
98fn run_clippy() -> Result<()> {
99 if cmd!("cargo clippy --version").read().is_err() {
100 bail!(
101 "Failed run cargo clippy. \
102 Please run `rustup component add clippy` to install it.",
103 )
172 } 104 }
105
106 let allowed_lints = "
107 -A clippy::collapsible_if
108 -A clippy::needless_pass_by_value
109 -A clippy::nonminimal_bool
110 -A clippy::redundant_pattern_matching
111 "
112 .split_ascii_whitespace();
113 cmd!("cargo clippy --all-features --all-targets -- {allowed_lints...}").run()?;
173 Ok(()) 114 Ok(())
174} 115}
116
117fn run_fuzzer() -> Result<()> {
118 let _d = pushd("./crates/syntax")?;
119 let _e = pushenv("RUSTUP_TOOLCHAIN", "nightly");
120 if cmd!("cargo fuzz --help").read().is_err() {
121 cmd!("cargo install cargo-fuzz").run()?;
122 };
123
124 // Expecting nightly rustc
125 let out = cmd!("rustc --version").read()?;
126 if !out.contains("nightly") {
127 bail!("fuzz tests require nightly rustc")
128 }
129
130 cmd!("cargo fuzz run parser").run()?;
131 Ok(())
132}
133
134fn date_iso() -> Result<String> {
135 let res = cmd!("date --iso --utc").read()?;
136 Ok(res)
137}
138
139fn is_release_tag(tag: &str) -> bool {
140 tag.len() == "2020-02-24".len() && tag.starts_with(|c: char| c.is_ascii_digit())
141}
142
143fn files_in(path: &Path, ext: &'static str) -> impl Iterator<Item = PathBuf> {
144 let iter = WalkDir::new(path);
145 return iter
146 .into_iter()
147 .filter_entry(|e| !is_hidden(e))
148 .map(|e| e.unwrap())
149 .filter(|e| !e.file_type().is_dir())
150 .map(|e| e.into_path())
151 .filter(move |path| path.extension().map(|it| it == ext).unwrap_or(false));
152
153 fn is_hidden(entry: &DirEntry) -> bool {
154 entry.file_name().to_str().map(|s| s.starts_with('.')).unwrap_or(false)
155 }
156}