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.rs286
1 files changed, 142 insertions, 144 deletions
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index cbb9b315e..ca27b6cec 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -7,168 +7,166 @@
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::{codegen::Mode, 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) => {
94 finish_args(args)?; 43 cmd.validate()?;
95 run_rustfmt(Mode::Overwrite) 44 cmd.run()
96 } 45 }
97 "install-pre-commit-hook" => { 46 flags::XtaskCmd::Codegen(cmd) => cmd.run(),
98 finish_args(args)?; 47 flags::XtaskCmd::Lint(_) => run_clippy(),
99 pre_commit::install_hook() 48 flags::XtaskCmd::FuzzTests(_) => run_fuzzer(),
49 flags::XtaskCmd::PreCache(cmd) => cmd.run(),
50 flags::XtaskCmd::Release(cmd) => cmd.run(),
51 flags::XtaskCmd::Promote(cmd) => cmd.run(),
52 flags::XtaskCmd::Dist(flags) => {
53 DistCmd { nightly: flags.nightly, client_version: flags.client }.run()
100 } 54 }
101 "lint" => { 55 flags::XtaskCmd::Metrics(cmd) => cmd.run(),
102 finish_args(args)?; 56 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 { 57 {
138 let _d = pushd("./crates/rust-analyzer")?; 58 let _d = pushd("./crates/rust-analyzer")?;
139 cmd!("cargo build --release --features jemalloc").run()?; 59 cmd!("cargo build --release --features jemalloc").run()?;
140 } 60 }
141 cp("./target/release/rust-analyzer", format!("./target/rust-analyzer-{}", suffix))?; 61 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(()) 62 Ok(())
165 } 63 }
166 } 64 }
167} 65}
168 66
169fn finish_args(args: Arguments) -> Result<()> { 67fn project_root() -> PathBuf {
170 if !args.finish().is_empty() { 68 Path::new(
171 bail!("Unused arguments."); 69 &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
70 )
71 .ancestors()
72 .nth(1)
73 .unwrap()
74 .to_path_buf()
75}
76
77fn rust_files() -> impl Iterator<Item = PathBuf> {
78 rust_files_in(&project_root().join("crates"))
79}
80
81#[cfg(test)]
82fn cargo_files() -> impl Iterator<Item = PathBuf> {
83 files_in(&project_root(), "toml")
84 .filter(|path| path.file_name().map(|it| it == "Cargo.toml").unwrap_or(false))
85}
86
87fn rust_files_in(path: &Path) -> impl Iterator<Item = PathBuf> {
88 files_in(path, "rs")
89}
90
91fn run_rustfmt(mode: Mode) -> Result<()> {
92 let _dir = pushd(project_root())?;
93 let _e = pushenv("RUSTUP_TOOLCHAIN", "stable");
94 ensure_rustfmt()?;
95 let check = match mode {
96 Mode::Overwrite => &[][..],
97 Mode::Verify => &["--", "--check"],
98 };
99 cmd!("cargo fmt {check...}").run()?;
100 Ok(())
101}
102
103fn ensure_rustfmt() -> Result<()> {
104 let out = cmd!("rustfmt --version").read()?;
105 if !out.contains("stable") {
106 bail!(
107 "Failed to run rustfmt from toolchain 'stable'. \
108 Please run `rustup component add rustfmt --toolchain stable` to install it.",
109 )
110 }
111 Ok(())
112}
113
114fn run_clippy() -> Result<()> {
115 if cmd!("cargo clippy --version").read().is_err() {
116 bail!(
117 "Failed run cargo clippy. \
118 Please run `rustup component add clippy` to install it.",
119 )
120 }
121
122 let allowed_lints = "
123 -A clippy::collapsible_if
124 -A clippy::needless_pass_by_value
125 -A clippy::nonminimal_bool
126 -A clippy::redundant_pattern_matching
127 "
128 .split_ascii_whitespace();
129 cmd!("cargo clippy --all-features --all-targets -- {allowed_lints...}").run()?;
130 Ok(())
131}
132
133fn run_fuzzer() -> Result<()> {
134 let _d = pushd("./crates/syntax")?;
135 let _e = pushenv("RUSTUP_TOOLCHAIN", "nightly");
136 if cmd!("cargo fuzz --help").read().is_err() {
137 cmd!("cargo install cargo-fuzz").run()?;
138 };
139
140 // Expecting nightly rustc
141 let out = cmd!("rustc --version").read()?;
142 if !out.contains("nightly") {
143 bail!("fuzz tests require nightly rustc")
172 } 144 }
145
146 cmd!("cargo fuzz run parser").run()?;
173 Ok(()) 147 Ok(())
174} 148}
149
150fn date_iso() -> Result<String> {
151 let res = cmd!("date --iso --utc").read()?;
152 Ok(res)
153}
154
155fn is_release_tag(tag: &str) -> bool {
156 tag.len() == "2020-02-24".len() && tag.starts_with(|c: char| c.is_ascii_digit())
157}
158
159fn files_in(path: &Path, ext: &'static str) -> impl Iterator<Item = PathBuf> {
160 let iter = WalkDir::new(path);
161 return iter
162 .into_iter()
163 .filter_entry(|e| !is_hidden(e))
164 .map(|e| e.unwrap())
165 .filter(|e| !e.file_type().is_dir())
166 .map(|e| e.into_path())
167 .filter(move |path| path.extension().map(|it| it == ext).unwrap_or(false));
168
169 fn is_hidden(entry: &DirEntry) -> bool {
170 entry.file_name().to_str().map(|s| s.starts_with('.')).unwrap_or(false)
171 }
172}