aboutsummaryrefslogtreecommitdiff
path: root/xtask
diff options
context:
space:
mode:
Diffstat (limited to 'xtask')
-rw-r--r--xtask/Cargo.toml2
-rw-r--r--xtask/src/codegen.rs78
-rw-r--r--xtask/src/codegen/gen_assists_docs.rs20
-rw-r--r--xtask/src/codegen/gen_diagnostic_docs.rs8
-rw-r--r--xtask/src/codegen/gen_feature_docs.rs8
-rw-r--r--xtask/src/codegen/gen_lint_completions.rs12
-rw-r--r--xtask/src/codegen/gen_parser_tests.rs12
-rw-r--r--xtask/src/codegen/gen_syntax.rs10
-rw-r--r--xtask/src/flags.rs51
-rw-r--r--xtask/src/install.rs120
-rw-r--r--xtask/src/main.rs45
-rw-r--r--xtask/src/release.rs5
-rw-r--r--xtask/src/tidy.rs50
13 files changed, 187 insertions, 234 deletions
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index b17dde598..e084f0df6 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -15,5 +15,5 @@ ungrammar = "=1.11"
15walkdir = "2.3.1" 15walkdir = "2.3.1"
16write-json = "0.1.0" 16write-json = "0.1.0"
17xshell = "0.1" 17xshell = "0.1"
18xflags = "0.1.2" 18xflags = "0.2.1"
19# Avoid adding more dependencies to this crate 19# Avoid adding more dependencies to this crate
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs
index 2f56c5ad0..2cf3c6fdc 100644
--- a/xtask/src/codegen.rs
+++ b/xtask/src/codegen.rs
@@ -7,68 +7,66 @@
7 7
8mod gen_syntax; 8mod gen_syntax;
9mod gen_parser_tests; 9mod gen_parser_tests;
10mod gen_lint_completions;
10mod gen_assists_docs; 11mod gen_assists_docs;
11mod gen_feature_docs; 12mod gen_feature_docs;
12mod gen_lint_completions;
13mod gen_diagnostic_docs; 13mod gen_diagnostic_docs;
14 14
15use std::{ 15use std::{
16 fmt, mem, 16 fmt, mem,
17 path::{Path, PathBuf}, 17 path::{Path, PathBuf},
18}; 18};
19use xshell::{cmd, pushenv, read_file, write_file}; 19use xshell::{cmd, pushenv};
20 20
21use crate::{ensure_rustfmt, flags, project_root, Result}; 21use crate::{ensure_rustfmt, project_root, Result};
22 22
23pub(crate) use self::{ 23pub(crate) use self::{
24 gen_assists_docs::{generate_assists_docs, generate_assists_tests}, 24 gen_assists_docs::generate_assists_tests, gen_lint_completions::generate_lint_completions,
25 gen_diagnostic_docs::generate_diagnostic_docs, 25 gen_parser_tests::generate_parser_tests, gen_syntax::generate_syntax,
26 gen_feature_docs::generate_feature_docs,
27 gen_lint_completions::generate_lint_completions,
28 gen_parser_tests::generate_parser_tests,
29 gen_syntax::generate_syntax,
30}; 26};
31 27
32#[derive(Debug, PartialEq, Eq, Clone, Copy)] 28pub(crate) fn docs() -> Result<()> {
33pub(crate) enum Mode { 29 // We don't commit docs to the repo, so we can just overwrite them.
34 Overwrite, 30 gen_assists_docs::generate_assists_docs()?;
35 Verify, 31 gen_feature_docs::generate_feature_docs()?;
32 gen_diagnostic_docs::generate_diagnostic_docs()?;
33 Ok(())
36} 34}
37 35
38impl flags::Codegen { 36#[allow(unused)]
39 pub(crate) fn run(self) -> Result<()> { 37fn used() {
40 if self.features { 38 generate_parser_tests();
41 generate_lint_completions(Mode::Overwrite)?; 39 generate_assists_tests();
42 } 40 generate_syntax();
43 generate_syntax(Mode::Overwrite)?; 41 generate_lint_completions();
44 generate_parser_tests(Mode::Overwrite)?;
45 generate_assists_tests(Mode::Overwrite)?;
46 generate_assists_docs(Mode::Overwrite)?;
47 generate_feature_docs(Mode::Overwrite)?;
48 generate_diagnostic_docs(Mode::Overwrite)?;
49 Ok(())
50 }
51} 42}
52 43
53/// A helper to update file on disk if it has changed. 44/// Checks that the `file` has the specified `contents`. If that is not the
54/// With verify = false, 45/// case, updates the file and then fails the test.
55fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { 46pub(crate) fn ensure_file_contents(file: &Path, contents: &str) -> Result<()> {
56 match read_file(path) { 47 match std::fs::read_to_string(file) {
57 Ok(old_contents) if normalize(&old_contents) == normalize(contents) => { 48 Ok(old_contents) if normalize_newlines(&old_contents) == normalize_newlines(contents) => {
58 return Ok(()); 49 return Ok(())
59 } 50 }
60 _ => (), 51 _ => (),
61 } 52 }
62 if mode == Mode::Verify { 53 let display_path = file.strip_prefix(&project_root()).unwrap_or(file);
63 anyhow::bail!("`{}` is not up-to-date", path.display()); 54 eprintln!(
55 "\n\x1b[31;1merror\x1b[0m: {} was not up-to-date, updating\n",
56 display_path.display()
57 );
58 if std::env::var("CI").is_ok() {
59 eprintln!(" NOTE: run `cargo test` locally and commit the updated files\n");
64 } 60 }
65 eprintln!("updating {}", path.display()); 61 if let Some(parent) = file.parent() {
66 write_file(path, contents)?; 62 let _ = std::fs::create_dir_all(parent);
67 return Ok(());
68
69 fn normalize(s: &str) -> String {
70 s.replace("\r\n", "\n")
71 } 63 }
64 std::fs::write(file, contents).unwrap();
65 anyhow::bail!("some file were not up to date")
66}
67
68fn normalize_newlines(s: &str) -> String {
69 s.replace("\r\n", "\n")
72} 70}
73 71
74const PREAMBLE: &str = "Generated file, do not edit by hand, see `xtask/src/codegen`"; 72const PREAMBLE: &str = "Generated file, do not edit by hand, see `xtask/src/codegen`";
diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs
index c469b388d..158680993 100644
--- a/xtask/src/codegen/gen_assists_docs.rs
+++ b/xtask/src/codegen/gen_assists_docs.rs
@@ -2,22 +2,25 @@
2 2
3use std::{fmt, path::Path}; 3use std::{fmt, path::Path};
4 4
5use xshell::write_file;
6
5use crate::{ 7use crate::{
6 codegen::{self, extract_comment_blocks_with_empty_lines, reformat, Location, Mode, PREAMBLE}, 8 codegen::{self, extract_comment_blocks_with_empty_lines, reformat, Location, PREAMBLE},
7 project_root, rust_files_in, Result, 9 project_root, rust_files_in, Result,
8}; 10};
9 11
10pub(crate) fn generate_assists_tests(mode: Mode) -> Result<()> { 12pub(crate) fn generate_assists_tests() -> Result<()> {
11 let assists = Assist::collect()?; 13 let assists = Assist::collect()?;
12 generate_tests(&assists, mode) 14 generate_tests(&assists)
13} 15}
14 16
15pub(crate) fn generate_assists_docs(mode: Mode) -> Result<()> { 17pub(crate) fn generate_assists_docs() -> Result<()> {
16 let assists = Assist::collect()?; 18 let assists = Assist::collect()?;
17 let contents = assists.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n"); 19 let contents = assists.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n");
18 let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim()); 20 let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim());
19 let dst = project_root().join("docs/user/generated_assists.adoc"); 21 let dst = project_root().join("docs/user/generated_assists.adoc");
20 codegen::update(&dst, &contents, mode) 22 write_file(dst, &contents)?;
23 Ok(())
21} 24}
22 25
23#[derive(Debug)] 26#[derive(Debug)]
@@ -111,7 +114,7 @@ impl fmt::Display for Assist {
111 } 114 }
112} 115}
113 116
114fn generate_tests(assists: &[Assist], mode: Mode) -> Result<()> { 117fn generate_tests(assists: &[Assist]) -> Result<()> {
115 let mut buf = String::from("use super::check_doc_test;\n"); 118 let mut buf = String::from("use super::check_doc_test;\n");
116 119
117 for assist in assists.iter() { 120 for assist in assists.iter() {
@@ -135,7 +138,10 @@ r#####"
135 buf.push_str(&test) 138 buf.push_str(&test)
136 } 139 }
137 let buf = reformat(&buf)?; 140 let buf = reformat(&buf)?;
138 codegen::update(&project_root().join("crates/ide_assists/src/tests/generated.rs"), &buf, mode) 141 codegen::ensure_file_contents(
142 &project_root().join("crates/ide_assists/src/tests/generated.rs"),
143 &buf,
144 )
139} 145}
140 146
141fn hide_hash_comments(text: &str) -> String { 147fn hide_hash_comments(text: &str) -> String {
diff --git a/xtask/src/codegen/gen_diagnostic_docs.rs b/xtask/src/codegen/gen_diagnostic_docs.rs
index a2561817b..9cf4d0a88 100644
--- a/xtask/src/codegen/gen_diagnostic_docs.rs
+++ b/xtask/src/codegen/gen_diagnostic_docs.rs
@@ -2,18 +2,20 @@
2 2
3use std::{fmt, path::PathBuf}; 3use std::{fmt, path::PathBuf};
4 4
5use xshell::write_file;
6
5use crate::{ 7use crate::{
6 codegen::{self, extract_comment_blocks_with_empty_lines, Location, Mode, PREAMBLE}, 8 codegen::{extract_comment_blocks_with_empty_lines, Location, PREAMBLE},
7 project_root, rust_files, Result, 9 project_root, rust_files, Result,
8}; 10};
9 11
10pub(crate) fn generate_diagnostic_docs(mode: Mode) -> Result<()> { 12pub(crate) fn generate_diagnostic_docs() -> Result<()> {
11 let diagnostics = Diagnostic::collect()?; 13 let diagnostics = Diagnostic::collect()?;
12 let contents = 14 let contents =
13 diagnostics.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n"); 15 diagnostics.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n");
14 let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim()); 16 let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim());
15 let dst = project_root().join("docs/user/generated_diagnostic.adoc"); 17 let dst = project_root().join("docs/user/generated_diagnostic.adoc");
16 codegen::update(&dst, &contents, mode)?; 18 write_file(&dst, &contents)?;
17 Ok(()) 19 Ok(())
18} 20}
19 21
diff --git a/xtask/src/codegen/gen_feature_docs.rs b/xtask/src/codegen/gen_feature_docs.rs
index cad7ff477..c373d7d70 100644
--- a/xtask/src/codegen/gen_feature_docs.rs
+++ b/xtask/src/codegen/gen_feature_docs.rs
@@ -2,17 +2,19 @@
2 2
3use std::{fmt, path::PathBuf}; 3use std::{fmt, path::PathBuf};
4 4
5use xshell::write_file;
6
5use crate::{ 7use crate::{
6 codegen::{self, extract_comment_blocks_with_empty_lines, Location, Mode, PREAMBLE}, 8 codegen::{extract_comment_blocks_with_empty_lines, Location, PREAMBLE},
7 project_root, rust_files, Result, 9 project_root, rust_files, Result,
8}; 10};
9 11
10pub(crate) fn generate_feature_docs(mode: Mode) -> Result<()> { 12pub(crate) fn generate_feature_docs() -> Result<()> {
11 let features = Feature::collect()?; 13 let features = Feature::collect()?;
12 let contents = features.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n"); 14 let contents = features.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n");
13 let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim()); 15 let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim());
14 let dst = project_root().join("docs/user/generated_features.adoc"); 16 let dst = project_root().join("docs/user/generated_features.adoc");
15 codegen::update(&dst, &contents, mode)?; 17 write_file(&dst, &contents)?;
16 Ok(()) 18 Ok(())
17} 19}
18 20
diff --git a/xtask/src/codegen/gen_lint_completions.rs b/xtask/src/codegen/gen_lint_completions.rs
index b1c057037..24dbc6a39 100644
--- a/xtask/src/codegen/gen_lint_completions.rs
+++ b/xtask/src/codegen/gen_lint_completions.rs
@@ -5,13 +5,10 @@ use std::path::{Path, PathBuf};
5use walkdir::WalkDir; 5use walkdir::WalkDir;
6use xshell::{cmd, read_file}; 6use xshell::{cmd, read_file};
7 7
8use crate::{ 8use crate::codegen::{ensure_file_contents, project_root, reformat, Result};
9 codegen::{project_root, reformat, update, Mode, Result},
10 run_rustfmt,
11};
12 9
13pub(crate) fn generate_lint_completions(mode: Mode) -> Result<()> { 10pub(crate) fn generate_lint_completions() -> Result<()> {
14 if !Path::new("./target/rust").exists() { 11 if !project_root().join("./target/rust").exists() {
15 cmd!("git clone --depth=1 https://github.com/rust-lang/rust ./target/rust").run()?; 12 cmd!("git clone --depth=1 https://github.com/rust-lang/rust ./target/rust").run()?;
16 } 13 }
17 14
@@ -25,8 +22,7 @@ pub(crate) fn generate_lint_completions(mode: Mode) -> Result<()> {
25 22
26 let destination = 23 let destination =
27 project_root().join("crates/ide_completion/src/generated_lint_completions.rs"); 24 project_root().join("crates/ide_completion/src/generated_lint_completions.rs");
28 update(destination.as_path(), &contents, mode)?; 25 ensure_file_contents(destination.as_path(), &contents)?;
29 run_rustfmt(mode)?;
30 26
31 Ok(()) 27 Ok(())
32} 28}
diff --git a/xtask/src/codegen/gen_parser_tests.rs b/xtask/src/codegen/gen_parser_tests.rs
index cb8939063..096590653 100644
--- a/xtask/src/codegen/gen_parser_tests.rs
+++ b/xtask/src/codegen/gen_parser_tests.rs
@@ -8,13 +8,13 @@ use std::{
8}; 8};
9 9
10use crate::{ 10use crate::{
11 codegen::{extract_comment_blocks, update, Mode}, 11 codegen::{ensure_file_contents, extract_comment_blocks},
12 project_root, Result, 12 project_root, Result,
13}; 13};
14 14
15pub(crate) fn generate_parser_tests(mode: Mode) -> Result<()> { 15pub(crate) fn generate_parser_tests() -> Result<()> {
16 let tests = tests_from_dir(&project_root().join(Path::new("crates/parser/src/grammar")))?; 16 let tests = tests_from_dir(&project_root().join(Path::new("crates/parser/src/grammar")))?;
17 fn install_tests(tests: &HashMap<String, Test>, into: &str, mode: Mode) -> Result<()> { 17 fn install_tests(tests: &HashMap<String, Test>, into: &str) -> Result<()> {
18 let tests_dir = project_root().join(into); 18 let tests_dir = project_root().join(into);
19 if !tests_dir.is_dir() { 19 if !tests_dir.is_dir() {
20 fs::create_dir_all(&tests_dir)?; 20 fs::create_dir_all(&tests_dir)?;
@@ -35,12 +35,12 @@ pub(crate) fn generate_parser_tests(mode: Mode) -> Result<()> {
35 tests_dir.join(file_name) 35 tests_dir.join(file_name)
36 } 36 }
37 }; 37 };
38 update(&path, &test.text, mode)?; 38 ensure_file_contents(&path, &test.text)?;
39 } 39 }
40 Ok(()) 40 Ok(())
41 } 41 }
42 install_tests(&tests.ok, "crates/syntax/test_data/parser/inline/ok", mode)?; 42 install_tests(&tests.ok, "crates/syntax/test_data/parser/inline/ok")?;
43 install_tests(&tests.err, "crates/syntax/test_data/parser/inline/err", mode) 43 install_tests(&tests.err, "crates/syntax/test_data/parser/inline/err")
44} 44}
45 45
46#[derive(Debug)] 46#[derive(Debug)]
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs
index 191bc0e9d..80f26e8f5 100644
--- a/xtask/src/codegen/gen_syntax.rs
+++ b/xtask/src/codegen/gen_syntax.rs
@@ -14,25 +14,25 @@ use ungrammar::{rust_grammar, Grammar, Rule};
14 14
15use crate::{ 15use crate::{
16 ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC}, 16 ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC},
17 codegen::{reformat, update, Mode}, 17 codegen::{ensure_file_contents, reformat},
18 project_root, Result, 18 project_root, Result,
19}; 19};
20 20
21pub(crate) fn generate_syntax(mode: Mode) -> Result<()> { 21pub(crate) fn generate_syntax() -> Result<()> {
22 let grammar = rust_grammar(); 22 let grammar = rust_grammar();
23 let ast = lower(&grammar); 23 let ast = lower(&grammar);
24 24
25 let syntax_kinds_file = project_root().join("crates/parser/src/syntax_kind/generated.rs"); 25 let syntax_kinds_file = project_root().join("crates/parser/src/syntax_kind/generated.rs");
26 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?; 26 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?;
27 update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?; 27 ensure_file_contents(syntax_kinds_file.as_path(), &syntax_kinds)?;
28 28
29 let ast_tokens_file = project_root().join("crates/syntax/src/ast/generated/tokens.rs"); 29 let ast_tokens_file = project_root().join("crates/syntax/src/ast/generated/tokens.rs");
30 let contents = generate_tokens(&ast)?; 30 let contents = generate_tokens(&ast)?;
31 update(ast_tokens_file.as_path(), &contents, mode)?; 31 ensure_file_contents(ast_tokens_file.as_path(), &contents)?;
32 32
33 let ast_nodes_file = project_root().join("crates/syntax/src/ast/generated/nodes.rs"); 33 let ast_nodes_file = project_root().join("crates/syntax/src/ast/generated/nodes.rs");
34 let contents = generate_nodes(KINDS_SRC, &ast)?; 34 let contents = generate_nodes(KINDS_SRC, &ast)?;
35 update(ast_nodes_file.as_path(), &contents, mode)?; 35 ensure_file_contents(ast_nodes_file.as_path(), &contents)?;
36 36
37 Ok(()) 37 Ok(())
38} 38}
diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs
index 5710fbdb5..48d1ad45e 100644
--- a/xtask/src/flags.rs
+++ b/xtask/src/flags.rs
@@ -1,6 +1,10 @@
1#![allow(unreachable_pub)] 1#![allow(unreachable_pub)]
2 2
3xflags::args_parser! { 3use crate::install::{ClientOpt, Malloc, ServerOpt};
4
5xflags::xflags! {
6 src "./src/flags.rs"
7
4 /// Run custom build command. 8 /// Run custom build command.
5 cmd xtask { 9 cmd xtask {
6 default cmd help { 10 default cmd help {
@@ -23,10 +27,6 @@ xflags::args_parser! {
23 optional --jemalloc 27 optional --jemalloc
24 } 28 }
25 29
26 cmd codegen {
27 optional --features
28 }
29
30 cmd lint {} 30 cmd lint {}
31 cmd fuzz-tests {} 31 cmd fuzz-tests {}
32 cmd pre-cache {} 32 cmd pre-cache {}
@@ -53,7 +53,7 @@ xflags::args_parser! {
53 53
54// generated start 54// generated start
55// The following code is generated by `xflags` macro. 55// The following code is generated by `xflags` macro.
56// Run `env XFLAGS_DUMP= cargo build` to regenerate. 56// Run `env UPDATE_XFLAGS=1 cargo build` to regenerate.
57#[derive(Debug)] 57#[derive(Debug)]
58pub struct Xtask { 58pub struct Xtask {
59 pub subcommand: XtaskCmd, 59 pub subcommand: XtaskCmd,
@@ -63,7 +63,6 @@ pub struct Xtask {
63pub enum XtaskCmd { 63pub enum XtaskCmd {
64 Help(Help), 64 Help(Help),
65 Install(Install), 65 Install(Install),
66 Codegen(Codegen),
67 Lint(Lint), 66 Lint(Lint),
68 FuzzTests(FuzzTests), 67 FuzzTests(FuzzTests),
69 PreCache(PreCache), 68 PreCache(PreCache),
@@ -89,18 +88,13 @@ pub struct Install {
89} 88}
90 89
91#[derive(Debug)] 90#[derive(Debug)]
92pub struct Codegen { 91pub struct Lint;
93 pub features: bool,
94}
95
96#[derive(Debug)]
97pub struct Lint {}
98 92
99#[derive(Debug)] 93#[derive(Debug)]
100pub struct FuzzTests {} 94pub struct FuzzTests;
101 95
102#[derive(Debug)] 96#[derive(Debug)]
103pub struct PreCache {} 97pub struct PreCache;
104 98
105#[derive(Debug)] 99#[derive(Debug)]
106pub struct Release { 100pub struct Release {
@@ -129,11 +123,32 @@ pub struct Bb {
129} 123}
130 124
131impl Xtask { 125impl Xtask {
132 pub const HELP: &'static str = Self::_HELP; 126 pub const HELP: &'static str = Self::HELP_;
133 127
134 pub fn from_env() -> xflags::Result<Self> { 128 pub fn from_env() -> xflags::Result<Self> {
135 let mut p = xflags::rt::Parser::new_from_env(); 129 Self::from_env_()
136 Self::_parse(&mut p)
137 } 130 }
138} 131}
139// generated end 132// generated end
133
134impl Install {
135 pub(crate) fn server(&self) -> Option<ServerOpt> {
136 if self.client && !self.server {
137 return None;
138 }
139 let malloc = if self.mimalloc {
140 Malloc::Mimalloc
141 } else if self.jemalloc {
142 Malloc::Jemalloc
143 } else {
144 Malloc::System
145 };
146 Some(ServerOpt { malloc })
147 }
148 pub(crate) fn client(&self) -> Option<ClientOpt> {
149 if !self.client && self.server {
150 return None;
151 }
152 Some(ClientOpt { code_bin: self.code_bin.clone() })
153 }
154}
diff --git a/xtask/src/install.rs b/xtask/src/install.rs
index ea2194248..177028b08 100644
--- a/xtask/src/install.rs
+++ b/xtask/src/install.rs
@@ -5,60 +5,32 @@ use std::{env, path::PathBuf, str};
5use anyhow::{bail, format_err, Context, Result}; 5use anyhow::{bail, format_err, Context, Result};
6use xshell::{cmd, pushd}; 6use xshell::{cmd, pushd};
7 7
8use crate::flags;
9
8// Latest stable, feel free to send a PR if this lags behind. 10// Latest stable, feel free to send a PR if this lags behind.
9const REQUIRED_RUST_VERSION: u32 = 50; 11const REQUIRED_RUST_VERSION: u32 = 50;
10 12
11pub(crate) struct InstallCmd { 13impl flags::Install {
12 pub(crate) client: Option<ClientOpt>, 14 pub(crate) fn run(self) -> Result<()> {
13 pub(crate) server: Option<ServerOpt>, 15 if cfg!(target_os = "macos") {
14} 16 fix_path_for_mac().context("Fix path for mac")?
15 17 }
16#[derive(Clone, Copy)] 18 if let Some(server) = self.server() {
17pub(crate) enum ClientOpt { 19 install_server(server).context("install server")?;
18 VsCode, 20 }
19 VsCodeExploration, 21 if let Some(client) = self.client() {
20 VsCodeInsiders, 22 install_client(client).context("install client")?;
21 VsCodium,
22 VsCodeOss,
23 Any,
24}
25
26impl ClientOpt {
27 pub(crate) const fn as_cmds(&self) -> &'static [&'static str] {
28 match self {
29 ClientOpt::VsCode => &["code"],
30 ClientOpt::VsCodeExploration => &["code-exploration"],
31 ClientOpt::VsCodeInsiders => &["code-insiders"],
32 ClientOpt::VsCodium => &["codium"],
33 ClientOpt::VsCodeOss => &["code-oss"],
34 ClientOpt::Any => &["code", "code-exploration", "code-insiders", "codium", "code-oss"],
35 } 23 }
24 Ok(())
36 } 25 }
37} 26}
38 27
39impl Default for ClientOpt { 28#[derive(Clone)]
40 fn default() -> Self { 29pub(crate) struct ClientOpt {
41 ClientOpt::Any 30 pub(crate) code_bin: Option<String>,
42 }
43} 31}
44 32
45impl std::str::FromStr for ClientOpt { 33const VS_CODES: &[&str] = &["code", "code-exploration", "code-insiders", "codium", "code-oss"];
46 type Err = anyhow::Error;
47
48 fn from_str(s: &str) -> Result<Self, Self::Err> {
49 [
50 ClientOpt::VsCode,
51 ClientOpt::VsCodeExploration,
52 ClientOpt::VsCodeInsiders,
53 ClientOpt::VsCodium,
54 ClientOpt::VsCodeOss,
55 ]
56 .iter()
57 .copied()
58 .find(|c| [s] == c.as_cmds())
59 .ok_or_else(|| anyhow::format_err!("no such client"))
60 }
61}
62 34
63pub(crate) struct ServerOpt { 35pub(crate) struct ServerOpt {
64 pub(crate) malloc: Malloc, 36 pub(crate) malloc: Malloc,
@@ -70,21 +42,6 @@ pub(crate) enum Malloc {
70 Jemalloc, 42 Jemalloc,
71} 43}
72 44
73impl InstallCmd {
74 pub(crate) fn run(self) -> Result<()> {
75 if cfg!(target_os = "macos") {
76 fix_path_for_mac().context("Fix path for mac")?
77 }
78 if let Some(server) = self.server {
79 install_server(server).context("install server")?;
80 }
81 if let Some(client) = self.client {
82 install_client(client).context("install client")?;
83 }
84 Ok(())
85 }
86}
87
88fn fix_path_for_mac() -> Result<()> { 45fn fix_path_for_mac() -> Result<()> {
89 let mut vscode_path: Vec<PathBuf> = { 46 let mut vscode_path: Vec<PathBuf> = {
90 const COMMON_APP_PATH: &str = 47 const COMMON_APP_PATH: &str =
@@ -121,21 +78,12 @@ fn fix_path_for_mac() -> Result<()> {
121fn install_client(client_opt: ClientOpt) -> Result<()> { 78fn install_client(client_opt: ClientOpt) -> Result<()> {
122 let _dir = pushd("./editors/code"); 79 let _dir = pushd("./editors/code");
123 80
124 let find_code = |f: fn(&str) -> bool| -> Result<&'static str> { 81 // Package extension.
125 client_opt.as_cmds().iter().copied().find(|bin| f(bin)).ok_or_else(|| { 82 if cfg!(unix) {
126 format_err!("Can't execute `code --version`. Perhaps it is not in $PATH?")
127 })
128 };
129
130 let installed_extensions = if cfg!(unix) {
131 cmd!("npm --version").run().context("`npm` is required to build the VS Code plugin")?; 83 cmd!("npm --version").run().context("`npm` is required to build the VS Code plugin")?;
132 cmd!("npm ci").run()?; 84 cmd!("npm ci").run()?;
133 85
134 cmd!("npm run package --scripts-prepend-node-path").run()?; 86 cmd!("npm run package --scripts-prepend-node-path").run()?;
135
136 let code = find_code(|bin| cmd!("{bin} --version").read().is_ok())?;
137 cmd!("{code} --install-extension rust-analyzer.vsix --force").run()?;
138 cmd!("{code} --list-extensions").read()?
139 } else { 87 } else {
140 cmd!("cmd.exe /c npm --version") 88 cmd!("cmd.exe /c npm --version")
141 .run() 89 .run()
@@ -143,8 +91,36 @@ fn install_client(client_opt: ClientOpt) -> Result<()> {
143 cmd!("cmd.exe /c npm ci").run()?; 91 cmd!("cmd.exe /c npm ci").run()?;
144 92
145 cmd!("cmd.exe /c npm run package").run()?; 93 cmd!("cmd.exe /c npm run package").run()?;
94 };
95
96 // Find the appropriate VS Code binary.
97 let lifetime_extender;
98 let candidates: &[&str] = match client_opt.code_bin.as_deref() {
99 Some(it) => {
100 lifetime_extender = [it];
101 &lifetime_extender[..]
102 }
103 None => VS_CODES,
104 };
105 let code = candidates
106 .iter()
107 .copied()
108 .find(|&bin| {
109 if cfg!(unix) {
110 cmd!("{bin} --version").read().is_ok()
111 } else {
112 cmd!("cmd.exe /c {bin}.cmd --version").read().is_ok()
113 }
114 })
115 .ok_or_else(|| {
116 format_err!("Can't execute `{} --version`. Perhaps it is not in $PATH?", candidates[0])
117 })?;
146 118
147 let code = find_code(|bin| cmd!("cmd.exe /c {bin}.cmd --version").read().is_ok())?; 119 // Install & verify.
120 let installed_extensions = if cfg!(unix) {
121 cmd!("{code} --install-extension rust-analyzer.vsix --force").run()?;
122 cmd!("{code} --list-extensions").read()?
123 } else {
148 cmd!("cmd.exe /c {code}.cmd --install-extension rust-analyzer.vsix --force").run()?; 124 cmd!("cmd.exe /c {code}.cmd --install-extension rust-analyzer.vsix --force").run()?;
149 cmd!("cmd.exe /c {code}.cmd --list-extensions").read()? 125 cmd!("cmd.exe /c {code}.cmd --list-extensions").read()?
150 }; 126 };
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index e419db7a7..35cc7c108 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -28,11 +28,7 @@ use std::{
28use walkdir::{DirEntry, WalkDir}; 28use walkdir::{DirEntry, WalkDir};
29use xshell::{cmd, cp, pushd, pushenv}; 29use xshell::{cmd, cp, pushd, pushenv};
30 30
31use crate::{ 31use crate::dist::DistCmd;
32 codegen::Mode,
33 dist::DistCmd,
34 install::{InstallCmd, Malloc, ServerOpt},
35};
36 32
37fn main() -> Result<()> { 33fn main() -> Result<()> {
38 let _d = pushd(project_root())?; 34 let _d = pushd(project_root())?;
@@ -43,32 +39,7 @@ fn main() -> Result<()> {
43 println!("{}", flags::Xtask::HELP); 39 println!("{}", flags::Xtask::HELP);
44 return Ok(()); 40 return Ok(());
45 } 41 }
46 flags::XtaskCmd::Install(flags) => { 42 flags::XtaskCmd::Install(cmd) => cmd.run(),
47 if flags.server && flags.client {
48 eprintln!(
49 "error: The argument `--server` cannot be used with `--client`\n\n\
50 For more information try --help"
51 );
52 return Ok(());
53 }
54
55 let malloc = if flags.mimalloc {
56 Malloc::Mimalloc
57 } else if flags.jemalloc {
58 Malloc::Jemalloc
59 } else {
60 Malloc::System
61 };
62
63 let client_bin = flags.code_bin.map(|it| it.parse()).transpose()?;
64
65 InstallCmd {
66 client: if flags.server { None } else { client_bin },
67 server: if flags.client { None } else { Some(ServerOpt { malloc }) },
68 }
69 .run()
70 }
71 flags::XtaskCmd::Codegen(cmd) => cmd.run(),
72 flags::XtaskCmd::Lint(_) => run_clippy(), 43 flags::XtaskCmd::Lint(_) => run_clippy(),
73 flags::XtaskCmd::FuzzTests(_) => run_fuzzer(), 44 flags::XtaskCmd::FuzzTests(_) => run_fuzzer(),
74 flags::XtaskCmd::PreCache(cmd) => cmd.run(), 45 flags::XtaskCmd::PreCache(cmd) => cmd.run(),
@@ -113,18 +84,6 @@ fn rust_files_in(path: &Path) -> impl Iterator<Item = PathBuf> {
113 files_in(path, "rs") 84 files_in(path, "rs")
114} 85}
115 86
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<()> { 87fn ensure_rustfmt() -> Result<()> {
129 let out = cmd!("rustfmt --version").read()?; 88 let out = cmd!("rustfmt --version").read()?;
130 if !out.contains("stable") { 89 if !out.contains("stable") {
diff --git a/xtask/src/release.rs b/xtask/src/release.rs
index d8d86fd63..dde5d14ee 100644
--- a/xtask/src/release.rs
+++ b/xtask/src/release.rs
@@ -2,7 +2,7 @@ use std::fmt::Write;
2 2
3use xshell::{cmd, cp, pushd, read_dir, write_file}; 3use xshell::{cmd, cp, pushd, read_dir, write_file};
4 4
5use crate::{codegen, date_iso, flags, is_release_tag, project_root, Mode, Result}; 5use crate::{codegen, date_iso, flags, is_release_tag, project_root, Result};
6 6
7impl flags::Release { 7impl flags::Release {
8 pub(crate) fn run(self) -> Result<()> { 8 pub(crate) fn run(self) -> Result<()> {
@@ -12,8 +12,7 @@ impl flags::Release {
12 cmd!("git reset --hard tags/nightly").run()?; 12 cmd!("git reset --hard tags/nightly").run()?;
13 cmd!("git push").run()?; 13 cmd!("git push").run()?;
14 } 14 }
15 codegen::generate_assists_docs(Mode::Overwrite)?; 15 codegen::docs()?;
16 codegen::generate_feature_docs(Mode::Overwrite)?;
17 16
18 let website_root = project_root().join("../rust-analyzer.github.io"); 17 let website_root = project_root().join("../rust-analyzer.github.io");
19 let changelog_dir = website_root.join("./thisweek/_posts"); 18 let changelog_dir = website_root.join("./thisweek/_posts");
diff --git a/xtask/src/tidy.rs b/xtask/src/tidy.rs
index 349ca14d0..1352d1218 100644
--- a/xtask/src/tidy.rs
+++ b/xtask/src/tidy.rs
@@ -3,48 +3,48 @@ use std::{
3 path::{Path, PathBuf}, 3 path::{Path, PathBuf},
4}; 4};
5 5
6use xshell::{cmd, read_file}; 6use xshell::{cmd, pushd, pushenv, read_file};
7 7
8use crate::{ 8use crate::{cargo_files, codegen, project_root, rust_files};
9 cargo_files,
10 codegen::{self, Mode},
11 project_root, run_rustfmt, rust_files,
12};
13 9
14#[test] 10#[test]
15fn generated_grammar_is_fresh() { 11fn generate_grammar() {
16 if let Err(error) = codegen::generate_syntax(Mode::Verify) { 12 codegen::generate_syntax().unwrap()
17 panic!("{}. Please update it by running `cargo xtask codegen`", error);
18 }
19} 13}
20 14
21#[test] 15#[test]
22fn generated_tests_are_fresh() { 16fn generate_parser_tests() {
23 if let Err(error) = codegen::generate_parser_tests(Mode::Verify) { 17 codegen::generate_parser_tests().unwrap()
24 panic!("{}. Please update tests by running `cargo xtask codegen`", error);
25 }
26} 18}
27 19
28#[test] 20#[test]
29fn generated_assists_are_fresh() { 21fn generate_assists_tests() {
30 if let Err(error) = codegen::generate_assists_tests(Mode::Verify) { 22 codegen::generate_assists_tests().unwrap();
31 panic!("{}. Please update assists by running `cargo xtask codegen`", error); 23}
32 } 24
25/// This clones rustc repo, and so is not worth to keep up-to-date. We update
26/// manually by un-ignoring the test from time to time.
27#[test]
28#[ignore]
29fn generate_lint_completions() {
30 codegen::generate_lint_completions().unwrap()
33} 31}
34 32
35#[test] 33#[test]
36fn check_code_formatting() { 34fn check_code_formatting() {
37 if let Err(error) = run_rustfmt(Mode::Verify) { 35 let _dir = pushd(project_root()).unwrap();
38 panic!("{}. Please format the code by running `cargo format`", error); 36 let _e = pushenv("RUSTUP_TOOLCHAIN", "stable");
37 crate::ensure_rustfmt().unwrap();
38 let res = cmd!("cargo fmt -- --check").run();
39 if !res.is_ok() {
40 let _ = cmd!("cargo fmt").run();
39 } 41 }
42 res.unwrap()
40} 43}
41 44
42#[test] 45#[test]
43fn smoke_test_docs_generation() { 46fn smoke_test_generate_documentation() {
44 // We don't commit docs to the repo, so we can just overwrite in tests. 47 codegen::docs().unwrap()
45 codegen::generate_assists_docs(Mode::Overwrite).unwrap();
46 codegen::generate_feature_docs(Mode::Overwrite).unwrap();
47 codegen::generate_diagnostic_docs(Mode::Overwrite).unwrap();
48} 48}
49 49
50#[test] 50#[test]