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.rs282
1 files changed, 161 insertions, 121 deletions
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index dec48629c..e419db7a7 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -7,57 +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 codegen::CodegenCmd; 17mod install;
14use pico_args::Arguments; 18mod release;
15use xshell::{cmd, cp, pushd}; 19mod dist;
16use xtask::{ 20mod metrics;
17 codegen::{self, Mode}, 21mod pre_cache;
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,
18 dist::DistCmd, 33 dist::DistCmd,
19 install::{InstallCmd, Malloc, ServerOpt}, 34 install::{InstallCmd, Malloc, ServerOpt},
20 metrics::MetricsCmd,
21 pre_cache::PreCacheCmd,
22 pre_commit, project_root,
23 release::{PromoteCmd, ReleaseCmd},
24 run_clippy, run_fuzzer, run_rustfmt, Result,
25}; 35};
26 36
27fn main() -> Result<()> { 37fn main() -> Result<()> {
28 if env::args().next().map(|it| it.contains("pre-commit")) == Some(true) {
29 return pre_commit::run_hook();
30 }
31
32 let _d = pushd(project_root())?; 38 let _d = pushd(project_root())?;
33 39
34 let mut args = Arguments::from_env(); 40 let flags = flags::Xtask::from_env()?;
35 let subcommand = args.subcommand()?.unwrap_or_default(); 41 match flags.subcommand {
36 42 flags::XtaskCmd::Help(_) => {
37 match subcommand.as_str() { 43 println!("{}", flags::Xtask::HELP);
38 "install" => { 44 return Ok(());
39 if args.contains(["-h", "--help"]) { 45 }
40 eprintln!( 46 flags::XtaskCmd::Install(flags) => {
41 "\ 47 if flags.server && flags.client {
42cargo xtask install
43Install rust-analyzer server or editor plugin.
44
45USAGE:
46 cargo xtask install [FLAGS]
47
48FLAGS:
49 --client[=CLIENT] Install only VS Code plugin.
50 CLIENT is one of 'code', 'code-exploration', 'code-insiders', 'codium', or 'code-oss'
51 --server Install only the language server
52 --mimalloc Use mimalloc for server
53 -h, --help Prints help information
54 "
55 );
56 return Ok(());
57 }
58 let server = args.contains("--server");
59 let client_code = args.contains("--client");
60 if server && client_code {
61 eprintln!( 48 eprintln!(
62 "error: The argument `--server` cannot be used with `--client`\n\n\ 49 "error: The argument `--server` cannot be used with `--client`\n\n\
63 For more information try --help" 50 For more information try --help"
@@ -65,93 +52,146 @@ FLAGS:
65 return Ok(()); 52 return Ok(());
66 } 53 }
67 54
68 let malloc = 55 let malloc = if flags.mimalloc {
69 if args.contains("--mimalloc") { Malloc::Mimalloc } else { Malloc::System }; 56 Malloc::Mimalloc
57 } else if flags.jemalloc {
58 Malloc::Jemalloc
59 } else {
60 Malloc::System
61 };
70 62
71 let client_opt = args.opt_value_from_str("--client")?; 63 let client_bin = flags.code_bin.map(|it| it.parse()).transpose()?;
72
73 args.finish()?;
74 64
75 InstallCmd { 65 InstallCmd {
76 client: if server { None } else { Some(client_opt.unwrap_or_default()) }, 66 client: if flags.server { None } else { client_bin },
77 server: if client_code { None } else { Some(ServerOpt { malloc }) }, 67 server: if flags.client { None } else { Some(ServerOpt { malloc }) },
78 } 68 }
79 .run() 69 .run()
80 } 70 }
81 "codegen" => { 71 flags::XtaskCmd::Codegen(cmd) => cmd.run(),
82 let features = args.contains("--features"); 72 flags::XtaskCmd::Lint(_) => run_clippy(),
83 args.finish()?; 73 flags::XtaskCmd::FuzzTests(_) => run_fuzzer(),
84 CodegenCmd { features }.run() 74 flags::XtaskCmd::PreCache(cmd) => cmd.run(),
85 } 75 flags::XtaskCmd::Release(cmd) => cmd.run(),
86 "format" => { 76 flags::XtaskCmd::Promote(cmd) => cmd.run(),
87 args.finish()?; 77 flags::XtaskCmd::Dist(flags) => {
88 run_rustfmt(Mode::Overwrite) 78 DistCmd { nightly: flags.nightly, client_version: flags.client }.run()
89 }
90 "install-pre-commit-hook" => {
91 args.finish()?;
92 pre_commit::install_hook()
93 } 79 }
94 "lint" => { 80 flags::XtaskCmd::Metrics(cmd) => cmd.run(),
95 args.finish()?; 81 flags::XtaskCmd::Bb(cmd) => {
96 run_clippy() 82 {
97 } 83 let _d = pushd("./crates/rust-analyzer")?;
98 "fuzz-tests" => { 84 cmd!("cargo build --release --features jemalloc").run()?;
99 args.finish()?; 85 }
100 run_fuzzer() 86 cp("./target/release/rust-analyzer", format!("./target/rust-analyzer-{}", cmd.suffix))?;
101 }
102 "pre-cache" => {
103 args.finish()?;
104 PreCacheCmd.run()
105 }
106 "release" => {
107 let dry_run = args.contains("--dry-run");
108 args.finish()?;
109 ReleaseCmd { dry_run }.run()
110 }
111 "promote" => {
112 let dry_run = args.contains("--dry-run");
113 args.finish()?;
114 PromoteCmd { dry_run }.run()
115 }
116 "dist" => {
117 let nightly = args.contains("--nightly");
118 let client_version: Option<String> = args.opt_value_from_str("--client")?;
119 args.finish()?;
120 DistCmd { nightly, client_version }.run()
121 }
122 "metrics" => {
123 let dry_run = args.contains("--dry-run");
124 args.finish()?;
125 MetricsCmd { dry_run }.run()
126 }
127 "bb" => {
128 let suffix: String = args.free_from_str()?.unwrap();
129 args.finish()?;
130 cmd!("cargo build --release").run()?;
131 cp("./target/release/rust-analyzer", format!("./target/rust-analyzer-{}", suffix))?;
132 Ok(())
133 }
134 _ => {
135 eprintln!(
136 "\
137cargo xtask
138Run custom build command.
139
140USAGE:
141 cargo xtask <SUBCOMMAND>
142
143SUBCOMMANDS:
144 format
145 install-pre-commit-hook
146 fuzz-tests
147 codegen
148 install
149 lint
150 dist
151 promote
152 bb"
153 );
154 Ok(()) 87 Ok(())
155 } 88 }
156 } 89 }
157} 90}
91
92fn project_root() -> PathBuf {
93 Path::new(
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")
169 }
170
171 cmd!("cargo fuzz run parser").run()?;
172 Ok(())
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}