mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-10 15:14:32 +00:00
Merge #11700
11700: ⬆️ xshell r=matklad a=matklad
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
83575c96ed
14 changed files with 247 additions and 212 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -2072,18 +2072,18 @@ checksum = "da260301476ad19a4733a0e930db8227a48ea04561e235a5102978145ec69fcc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xshell"
|
name = "xshell"
|
||||||
version = "0.1.17"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eaad2035244c56da05573d4d7fda5f903c60a5f35b9110e157a14a1df45a9f14"
|
checksum = "3332cab90be2998a2aacb6494db45344bd16dfcc43ff36c42255018c6bcc96be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"xshell-macros",
|
"xshell-macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xshell-macros"
|
name = "xshell-macros"
|
||||||
version = "0.1.17"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4916a4a3cad759e499a3620523bf9545cc162d7a06163727dde97ce9aaa4cf39"
|
checksum = "f47e54cffa76000b7641328ab3bb1e146f93a1690ab86c5909c656f49d91019c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xtask"
|
name = "xtask"
|
||||||
|
|
|
@ -35,5 +35,5 @@ limit = { path = "../limit", version = "0.0.0" }
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
test_utils = { path = "../test_utils" }
|
test_utils = { path = "../test_utils" }
|
||||||
sourcegen = { path = "../sourcegen" }
|
sourcegen = { path = "../sourcegen" }
|
||||||
xshell = "0.1"
|
xshell = "0.2.0"
|
||||||
expect-test = "1.2.0-pre.1"
|
expect-test = "1.2.0-pre.1"
|
||||||
|
|
|
@ -4,16 +4,20 @@ use std::{borrow::Cow, fs, path::Path};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use stdx::format_to;
|
use stdx::format_to;
|
||||||
use test_utils::project_root;
|
use test_utils::project_root;
|
||||||
use xshell::cmd;
|
use xshell::{cmd, Shell};
|
||||||
|
|
||||||
/// This clones rustc repo, and so is not worth to keep up-to-date. We update
|
/// This clones rustc repo, and so is not worth to keep up-to-date. We update
|
||||||
/// manually by un-ignoring the test from time to time.
|
/// manually by un-ignoring the test from time to time.
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn sourcegen_lint_completions() {
|
fn sourcegen_lint_completions() {
|
||||||
|
let sh = &Shell::new().unwrap();
|
||||||
|
|
||||||
let rust_repo = project_root().join("./target/rust");
|
let rust_repo = project_root().join("./target/rust");
|
||||||
if !rust_repo.exists() {
|
if !rust_repo.exists() {
|
||||||
cmd!("git clone --depth=1 https://github.com/rust-lang/rust {rust_repo}").run().unwrap();
|
cmd!(sh, "git clone --depth=1 https://github.com/rust-lang/rust {rust_repo}")
|
||||||
|
.run()
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut contents = String::from(
|
let mut contents = String::from(
|
||||||
|
@ -30,16 +34,19 @@ pub struct LintGroup {
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
|
|
||||||
generate_lint_descriptor(&mut contents);
|
generate_lint_descriptor(sh, &mut contents);
|
||||||
contents.push('\n');
|
contents.push('\n');
|
||||||
|
|
||||||
generate_feature_descriptor(&mut contents, &rust_repo.join("src/doc/unstable-book/src"));
|
generate_feature_descriptor(&mut contents, &rust_repo.join("src/doc/unstable-book/src"));
|
||||||
contents.push('\n');
|
contents.push('\n');
|
||||||
|
|
||||||
let lints_json = project_root().join("./target/clippy_lints.json");
|
let lints_json = project_root().join("./target/clippy_lints.json");
|
||||||
cmd!("curl https://rust-lang.github.io/rust-clippy/master/lints.json --output {lints_json}")
|
cmd!(
|
||||||
.run()
|
sh,
|
||||||
.unwrap();
|
"curl https://rust-lang.github.io/rust-clippy/master/lints.json --output {lints_json}"
|
||||||
|
)
|
||||||
|
.run()
|
||||||
|
.unwrap();
|
||||||
generate_descriptor_clippy(&mut contents, &lints_json);
|
generate_descriptor_clippy(&mut contents, &lints_json);
|
||||||
|
|
||||||
let contents = sourcegen::add_preamble("sourcegen_lints", sourcegen::reformat(contents));
|
let contents = sourcegen::add_preamble("sourcegen_lints", sourcegen::reformat(contents));
|
||||||
|
@ -48,10 +55,10 @@ pub struct LintGroup {
|
||||||
sourcegen::ensure_file_contents(destination.as_path(), &contents);
|
sourcegen::ensure_file_contents(destination.as_path(), &contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_lint_descriptor(buf: &mut String) {
|
fn generate_lint_descriptor(sh: &Shell, buf: &mut String) {
|
||||||
// FIXME: rustdoc currently requires an input file for -Whelp cc https://github.com/rust-lang/rust/pull/88831
|
// FIXME: rustdoc currently requires an input file for -Whelp cc https://github.com/rust-lang/rust/pull/88831
|
||||||
let file = project_root().join(file!());
|
let file = project_root().join(file!());
|
||||||
let stdout = cmd!("rustdoc -W help {file}").read().unwrap();
|
let stdout = cmd!(sh, "rustdoc -W help {file}").read().unwrap();
|
||||||
let start_lints = stdout.find("---- ------- -------").unwrap();
|
let start_lints = stdout.find("---- ------- -------").unwrap();
|
||||||
let start_lint_groups = stdout.find("---- ---------").unwrap();
|
let start_lint_groups = stdout.find("---- ---------").unwrap();
|
||||||
let start_lints_rustdoc =
|
let start_lints_rustdoc =
|
||||||
|
|
|
@ -75,7 +75,7 @@ jemallocator = { version = "0.4.1", package = "tikv-jemallocator", optional = tr
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
expect-test = "1.2.0-pre.1"
|
expect-test = "1.2.0-pre.1"
|
||||||
jod-thread = "0.1.0"
|
jod-thread = "0.1.0"
|
||||||
xshell = "0.1"
|
xshell = "0.2.0"
|
||||||
|
|
||||||
test_utils = { path = "../test_utils" }
|
test_utils = { path = "../test_utils" }
|
||||||
sourcegen = { path = "../sourcegen" }
|
sourcegen = { path = "../sourcegen" }
|
||||||
|
|
|
@ -3,14 +3,15 @@ use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use xshell::{cmd, pushd, pushenv, read_file};
|
use xshell::{cmd, Shell};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_code_formatting() {
|
fn check_code_formatting() {
|
||||||
let _dir = pushd(sourcegen::project_root()).unwrap();
|
let sh = &Shell::new().unwrap();
|
||||||
let _e = pushenv("RUSTUP_TOOLCHAIN", "stable");
|
sh.change_dir(sourcegen::project_root());
|
||||||
|
sh.set_var("RUSTUP_TOOLCHAIN", "stable");
|
||||||
|
|
||||||
let out = cmd!("rustfmt --version").read().unwrap();
|
let out = cmd!(sh, "rustfmt --version").read().unwrap();
|
||||||
if !out.contains("stable") {
|
if !out.contains("stable") {
|
||||||
panic!(
|
panic!(
|
||||||
"Failed to run rustfmt from toolchain 'stable'. \
|
"Failed to run rustfmt from toolchain 'stable'. \
|
||||||
|
@ -18,25 +19,27 @@ fn check_code_formatting() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = cmd!("cargo fmt -- --check").run();
|
let res = cmd!(sh, "cargo fmt -- --check").run();
|
||||||
if res.is_err() {
|
if res.is_err() {
|
||||||
let _ = cmd!("cargo fmt").run();
|
let _ = cmd!(sh, "cargo fmt").run();
|
||||||
}
|
}
|
||||||
res.unwrap()
|
res.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_lsp_extensions_docs() {
|
fn check_lsp_extensions_docs() {
|
||||||
|
let sh = &Shell::new().unwrap();
|
||||||
|
|
||||||
let expected_hash = {
|
let expected_hash = {
|
||||||
let lsp_ext_rs =
|
let lsp_ext_rs = sh
|
||||||
read_file(sourcegen::project_root().join("crates/rust-analyzer/src/lsp_ext.rs"))
|
.read_file(sourcegen::project_root().join("crates/rust-analyzer/src/lsp_ext.rs"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
stable_hash(lsp_ext_rs.as_str())
|
stable_hash(lsp_ext_rs.as_str())
|
||||||
};
|
};
|
||||||
|
|
||||||
let actual_hash = {
|
let actual_hash = {
|
||||||
let lsp_extensions_md =
|
let lsp_extensions_md =
|
||||||
read_file(sourcegen::project_root().join("docs/dev/lsp-extensions.md")).unwrap();
|
sh.read_file(sourcegen::project_root().join("docs/dev/lsp-extensions.md")).unwrap();
|
||||||
let text = lsp_extensions_md
|
let text = lsp_extensions_md
|
||||||
.lines()
|
.lines()
|
||||||
.find_map(|line| line.strip_prefix("lsp_ext.rs hash:"))
|
.find_map(|line| line.strip_prefix("lsp_ext.rs hash:"))
|
||||||
|
@ -62,6 +65,8 @@ Please adjust docs/dev/lsp-extensions.md.
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn files_are_tidy() {
|
fn files_are_tidy() {
|
||||||
|
let sh = &Shell::new().unwrap();
|
||||||
|
|
||||||
let files = sourcegen::list_files(&sourcegen::project_root().join("crates"));
|
let files = sourcegen::list_files(&sourcegen::project_root().join("crates"));
|
||||||
|
|
||||||
let mut tidy_docs = TidyDocs::default();
|
let mut tidy_docs = TidyDocs::default();
|
||||||
|
@ -70,7 +75,7 @@ fn files_are_tidy() {
|
||||||
let extension = path.extension().unwrap_or_default().to_str().unwrap_or_default();
|
let extension = path.extension().unwrap_or_default().to_str().unwrap_or_default();
|
||||||
match extension {
|
match extension {
|
||||||
"rs" => {
|
"rs" => {
|
||||||
let text = read_file(&path).unwrap();
|
let text = sh.read_file(&path).unwrap();
|
||||||
check_todo(&path, &text);
|
check_todo(&path, &text);
|
||||||
check_dbg(&path, &text);
|
check_dbg(&path, &text);
|
||||||
check_test_attrs(&path, &text);
|
check_test_attrs(&path, &text);
|
||||||
|
@ -80,7 +85,7 @@ fn files_are_tidy() {
|
||||||
tidy_marks.visit(&path, &text);
|
tidy_marks.visit(&path, &text);
|
||||||
}
|
}
|
||||||
"toml" => {
|
"toml" => {
|
||||||
let text = read_file(&path).unwrap();
|
let text = sh.read_file(&path).unwrap();
|
||||||
check_cargo_toml(&path, text);
|
check_cargo_toml(&path, text);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
@ -139,8 +144,10 @@ fn check_cargo_toml(path: &Path, text: String) {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_merge_commits() {
|
fn check_merge_commits() {
|
||||||
let bors = cmd!("git rev-list --merges --author 'bors\\[bot\\]' HEAD~19..").read().unwrap();
|
let sh = &Shell::new().unwrap();
|
||||||
let all = cmd!("git rev-list --merges HEAD~19..").read().unwrap();
|
|
||||||
|
let bors = cmd!(sh, "git rev-list --merges --author 'bors\\[bot\\]' HEAD~19..").read().unwrap();
|
||||||
|
let all = cmd!(sh, "git rev-list --merges HEAD~19..").read().unwrap();
|
||||||
if bors != all {
|
if bors != all {
|
||||||
panic!(
|
panic!(
|
||||||
"
|
"
|
||||||
|
@ -213,6 +220,8 @@ See https://github.com/rust-lang/rust-clippy/issues/5537 for discussion.
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_licenses() {
|
fn check_licenses() {
|
||||||
|
let sh = &Shell::new().unwrap();
|
||||||
|
|
||||||
let expected = "
|
let expected = "
|
||||||
0BSD OR MIT OR Apache-2.0
|
0BSD OR MIT OR Apache-2.0
|
||||||
Apache-2.0
|
Apache-2.0
|
||||||
|
@ -235,7 +244,7 @@ Zlib OR Apache-2.0 OR MIT
|
||||||
.filter(|it| !it.is_empty())
|
.filter(|it| !it.is_empty())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let meta = cmd!("cargo metadata --format-version 1").read().unwrap();
|
let meta = cmd!(sh, "cargo metadata --format-version 1").read().unwrap();
|
||||||
let mut licenses = meta
|
let mut licenses = meta
|
||||||
.split(|c| c == ',' || c == '{' || c == '}')
|
.split(|c| c == ',' || c == '{' || c == '}')
|
||||||
.filter(|it| it.contains(r#""license""#))
|
.filter(|it| it.contains(r#""license""#))
|
||||||
|
|
|
@ -10,4 +10,4 @@ rust-version = "1.57"
|
||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
xshell = "0.1"
|
xshell = "0.2.0"
|
||||||
|
|
|
@ -11,7 +11,7 @@ use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use xshell::{cmd, pushenv};
|
use xshell::{cmd, Shell};
|
||||||
|
|
||||||
pub fn list_rust_files(dir: &Path) -> Vec<PathBuf> {
|
pub fn list_rust_files(dir: &Path) -> Vec<PathBuf> {
|
||||||
let mut res = list_files(dir);
|
let mut res = list_files(dir);
|
||||||
|
@ -133,8 +133,8 @@ impl fmt::Display for Location {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_rustfmt() {
|
fn ensure_rustfmt(sh: &Shell) {
|
||||||
let version = cmd!("rustfmt --version").read().unwrap_or_default();
|
let version = cmd!(sh, "rustfmt --version").read().unwrap_or_default();
|
||||||
if !version.contains("stable") {
|
if !version.contains("stable") {
|
||||||
panic!(
|
panic!(
|
||||||
"Failed to run rustfmt from toolchain 'stable'. \
|
"Failed to run rustfmt from toolchain 'stable'. \
|
||||||
|
@ -144,10 +144,11 @@ fn ensure_rustfmt() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reformat(text: String) -> String {
|
pub fn reformat(text: String) -> String {
|
||||||
let _e = pushenv("RUSTUP_TOOLCHAIN", "stable");
|
let sh = Shell::new().unwrap();
|
||||||
ensure_rustfmt();
|
sh.set_var("RUSTUP_TOOLCHAIN", "stable");
|
||||||
|
ensure_rustfmt(&sh);
|
||||||
let rustfmt_toml = project_root().join("rustfmt.toml");
|
let rustfmt_toml = project_root().join("rustfmt.toml");
|
||||||
let mut stdout = cmd!("rustfmt --config-path {rustfmt_toml} --config fn_single_line=true")
|
let mut stdout = cmd!(sh, "rustfmt --config-path {rustfmt_toml} --config fn_single_line=true")
|
||||||
.stdin(text)
|
.stdin(text)
|
||||||
.read()
|
.read()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -10,6 +10,6 @@ rust-version = "1.57"
|
||||||
anyhow = "1.0.26"
|
anyhow = "1.0.26"
|
||||||
flate2 = "1.0"
|
flate2 = "1.0"
|
||||||
write-json = "0.1.0"
|
write-json = "0.1.0"
|
||||||
xshell = "0.1"
|
xshell = "0.2.0"
|
||||||
xflags = "0.2.1"
|
xflags = "0.2.1"
|
||||||
# Avoid adding more dependencies to this crate
|
# Avoid adding more dependencies to this crate
|
||||||
|
|
|
@ -5,25 +5,23 @@ use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use flate2::{write::GzEncoder, Compression};
|
use flate2::{write::GzEncoder, Compression};
|
||||||
use xshell::{cmd, cp, mkdir_p, pushd, pushenv, read_file, rm_rf, write_file};
|
use xshell::{cmd, Shell};
|
||||||
|
|
||||||
use crate::{date_iso, flags, project_root};
|
use crate::{date_iso, flags, project_root};
|
||||||
|
|
||||||
impl flags::Dist {
|
impl flags::Dist {
|
||||||
pub(crate) fn run(self) -> Result<()> {
|
pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
|
||||||
let stable =
|
let stable = sh.var("GITHUB_REF").unwrap_or_default().as_str() == "refs/heads/release";
|
||||||
std::env::var("GITHUB_REF").unwrap_or_default().as_str() == "refs/heads/release";
|
|
||||||
|
|
||||||
let project_root = project_root();
|
let project_root = project_root();
|
||||||
let target = Target::get(&project_root);
|
let target = Target::get(&project_root);
|
||||||
let dist = project_root.join("dist");
|
let dist = project_root.join("dist");
|
||||||
rm_rf(&dist)?;
|
sh.remove_path(&dist)?;
|
||||||
mkdir_p(&dist)?;
|
sh.create_dir(&dist)?;
|
||||||
|
|
||||||
let release_channel = if stable { "stable" } else { "nightly" };
|
let release_channel = if stable { "stable" } else { "nightly" };
|
||||||
dist_server(release_channel, &target)?;
|
dist_server(sh, release_channel, &target)?;
|
||||||
|
|
||||||
if let Some(patch_version) = self.client_patch_version {
|
if let Some(patch_version) = self.client_patch_version {
|
||||||
let version = if stable {
|
let version = if stable {
|
||||||
|
@ -32,50 +30,55 @@ impl flags::Dist {
|
||||||
// A hack to make VS Code prefer nightly over stable.
|
// A hack to make VS Code prefer nightly over stable.
|
||||||
format!("0.3.{}", patch_version)
|
format!("0.3.{}", patch_version)
|
||||||
};
|
};
|
||||||
let release_tag = if stable { date_iso()? } else { "nightly".to_string() };
|
let release_tag = if stable { date_iso(sh)? } else { "nightly".to_string() };
|
||||||
dist_client(&version, &release_tag, &target)?;
|
dist_client(sh, &version, &release_tag, &target)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dist_client(version: &str, release_tag: &str, target: &Target) -> Result<()> {
|
fn dist_client(
|
||||||
|
sh: &Shell,
|
||||||
|
version: &str,
|
||||||
|
release_tag: &str,
|
||||||
|
target: &Target,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
let bundle_path = Path::new("editors").join("code").join("server");
|
let bundle_path = Path::new("editors").join("code").join("server");
|
||||||
mkdir_p(&bundle_path)?;
|
sh.create_dir(&bundle_path)?;
|
||||||
cp(&target.server_path, &bundle_path)?;
|
sh.copy_file(&target.server_path, &bundle_path)?;
|
||||||
if let Some(symbols_path) = &target.symbols_path {
|
if let Some(symbols_path) = &target.symbols_path {
|
||||||
cp(symbols_path, &bundle_path)?;
|
sh.copy_file(symbols_path, &bundle_path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let _d = pushd("./editors/code")?;
|
let _d = sh.push_dir("./editors/code");
|
||||||
|
|
||||||
let mut patch = Patch::new("./package.json")?;
|
let mut patch = Patch::new(sh, "./package.json")?;
|
||||||
patch
|
patch
|
||||||
.replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version))
|
.replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version))
|
||||||
.replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag))
|
.replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag))
|
||||||
.replace(r#""$generated-start": {},"#, "")
|
.replace(r#""$generated-start": {},"#, "")
|
||||||
.replace(",\n \"$generated-end\": {}", "")
|
.replace(",\n \"$generated-end\": {}", "")
|
||||||
.replace(r#""enabledApiProposals": [],"#, r#""#);
|
.replace(r#""enabledApiProposals": [],"#, r#""#);
|
||||||
patch.commit()?;
|
patch.commit(sh)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dist_server(release_channel: &str, target: &Target) -> Result<()> {
|
fn dist_server(sh: &Shell, release_channel: &str, target: &Target) -> anyhow::Result<()> {
|
||||||
let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel);
|
let _e = sh.push_env("RUST_ANALYZER_CHANNEL", release_channel);
|
||||||
let _e = pushenv("CARGO_PROFILE_RELEASE_LTO", "thin");
|
let _e = sh.push_env("CARGO_PROFILE_RELEASE_LTO", "thin");
|
||||||
|
|
||||||
// Uncomment to enable debug info for releases. Note that:
|
// Uncomment to enable debug info for releases. Note that:
|
||||||
// * debug info is split on windows and macs, so it does nothing for those platforms,
|
// * debug info is split on windows and macs, so it does nothing for those platforms,
|
||||||
// * on Linux, this blows up the binary size from 8MB to 43MB, which is unreasonable.
|
// * on Linux, this blows up the binary size from 8MB to 43MB, which is unreasonable.
|
||||||
// let _e = pushenv("CARGO_PROFILE_RELEASE_DEBUG", "1");
|
// let _e = sh.push_env("CARGO_PROFILE_RELEASE_DEBUG", "1");
|
||||||
|
|
||||||
if target.name.contains("-linux-") {
|
if target.name.contains("-linux-") {
|
||||||
env::set_var("CC", "clang");
|
env::set_var("CC", "clang");
|
||||||
}
|
}
|
||||||
|
|
||||||
let target_name = &target.name;
|
let target_name = &target.name;
|
||||||
cmd!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} --release").run()?;
|
cmd!(sh, "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} --release").run()?;
|
||||||
|
|
||||||
let dst = Path::new("dist").join(&target.artifact_name);
|
let dst = Path::new("dist").join(&target.artifact_name);
|
||||||
gzip(&target.server_path, &dst.with_extension("gz"))?;
|
gzip(&target.server_path, &dst.with_extension("gz"))?;
|
||||||
|
@ -83,7 +86,7 @@ fn dist_server(release_channel: &str, target: &Target) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> {
|
fn gzip(src_path: &Path, dest_path: &Path) -> anyhow::Result<()> {
|
||||||
let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best());
|
let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best());
|
||||||
let mut input = io::BufReader::new(File::open(src_path)?);
|
let mut input = io::BufReader::new(File::open(src_path)?);
|
||||||
io::copy(&mut input, &mut encoder)?;
|
io::copy(&mut input, &mut encoder)?;
|
||||||
|
@ -133,9 +136,9 @@ struct Patch {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Patch {
|
impl Patch {
|
||||||
fn new(path: impl Into<PathBuf>) -> Result<Patch> {
|
fn new(sh: &Shell, path: impl Into<PathBuf>) -> anyhow::Result<Patch> {
|
||||||
let path = path.into();
|
let path = path.into();
|
||||||
let contents = read_file(&path)?;
|
let contents = sh.read_file(&path)?;
|
||||||
Ok(Patch { path, original_contents: contents.clone(), contents })
|
Ok(Patch { path, original_contents: contents.clone(), contents })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,8 +148,8 @@ impl Patch {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn commit(&self) -> Result<()> {
|
fn commit(&self, sh: &Shell) -> anyhow::Result<()> {
|
||||||
write_file(&self.path, &self.contents)?;
|
sh.write_file(&self.path, &self.contents)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,20 +3,20 @@
|
||||||
use std::{env, path::PathBuf, str};
|
use std::{env, path::PathBuf, str};
|
||||||
|
|
||||||
use anyhow::{bail, format_err, Context, Result};
|
use anyhow::{bail, format_err, Context, Result};
|
||||||
use xshell::{cmd, pushd};
|
use xshell::{cmd, Shell};
|
||||||
|
|
||||||
use crate::flags;
|
use crate::flags;
|
||||||
|
|
||||||
impl flags::Install {
|
impl flags::Install {
|
||||||
pub(crate) fn run(self) -> Result<()> {
|
pub(crate) fn run(self, sh: &Shell) -> Result<()> {
|
||||||
if cfg!(target_os = "macos") {
|
if cfg!(target_os = "macos") {
|
||||||
fix_path_for_mac().context("Fix path for mac")?;
|
fix_path_for_mac(sh).context("Fix path for mac")?;
|
||||||
}
|
}
|
||||||
if let Some(server) = self.server() {
|
if let Some(server) = self.server() {
|
||||||
install_server(server).context("install server")?;
|
install_server(sh, server).context("install server")?;
|
||||||
}
|
}
|
||||||
if let Some(client) = self.client() {
|
if let Some(client) = self.client() {
|
||||||
install_client(client).context("install client")?;
|
install_client(sh, client).context("install client")?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -39,15 +39,14 @@ pub(crate) enum Malloc {
|
||||||
Jemalloc,
|
Jemalloc,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fix_path_for_mac() -> Result<()> {
|
fn fix_path_for_mac(sh: &Shell) -> Result<()> {
|
||||||
let mut vscode_path: Vec<PathBuf> = {
|
let mut vscode_path: Vec<PathBuf> = {
|
||||||
const COMMON_APP_PATH: &str =
|
const COMMON_APP_PATH: &str =
|
||||||
r"/Applications/Visual Studio Code.app/Contents/Resources/app/bin";
|
r"/Applications/Visual Studio Code.app/Contents/Resources/app/bin";
|
||||||
const ROOT_DIR: &str = "";
|
const ROOT_DIR: &str = "";
|
||||||
let home_dir = match env::var("HOME") {
|
let home_dir = sh.var("HOME").map_err(|err| {
|
||||||
Ok(home) => home,
|
format_err!("Failed getting HOME from environment with error: {}.", err)
|
||||||
Err(e) => bail!("Failed getting HOME from environment with error: {}.", e),
|
})?;
|
||||||
};
|
|
||||||
|
|
||||||
[ROOT_DIR, &home_dir]
|
[ROOT_DIR, &home_dir]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -58,36 +57,33 @@ fn fix_path_for_mac() -> Result<()> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if !vscode_path.is_empty() {
|
if !vscode_path.is_empty() {
|
||||||
let vars = match env::var_os("PATH") {
|
let vars = sh.var_os("PATH").context("Could not get PATH variable from env.")?;
|
||||||
Some(path) => path,
|
|
||||||
None => bail!("Could not get PATH variable from env."),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut paths = env::split_paths(&vars).collect::<Vec<_>>();
|
let mut paths = env::split_paths(&vars).collect::<Vec<_>>();
|
||||||
paths.append(&mut vscode_path);
|
paths.append(&mut vscode_path);
|
||||||
let new_paths = env::join_paths(paths).context("build env PATH")?;
|
let new_paths = env::join_paths(paths).context("build env PATH")?;
|
||||||
env::set_var("PATH", &new_paths);
|
sh.set_var("PATH", &new_paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install_client(client_opt: ClientOpt) -> Result<()> {
|
fn install_client(sh: &Shell, client_opt: ClientOpt) -> Result<()> {
|
||||||
let _dir = pushd("./editors/code");
|
let _dir = sh.push_dir("./editors/code");
|
||||||
|
|
||||||
// Package extension.
|
// Package extension.
|
||||||
if cfg!(unix) {
|
if cfg!(unix) {
|
||||||
cmd!("npm --version").run().context("`npm` is required to build the VS Code plugin")?;
|
cmd!(sh, "npm --version").run().context("`npm` is required to build the VS Code plugin")?;
|
||||||
cmd!("npm ci").run()?;
|
cmd!(sh, "npm ci").run()?;
|
||||||
|
|
||||||
cmd!("npm run package --scripts-prepend-node-path").run()?;
|
cmd!(sh, "npm run package --scripts-prepend-node-path").run()?;
|
||||||
} else {
|
} else {
|
||||||
cmd!("cmd.exe /c npm --version")
|
cmd!(sh, "cmd.exe /c npm --version")
|
||||||
.run()
|
.run()
|
||||||
.context("`npm` is required to build the VS Code plugin")?;
|
.context("`npm` is required to build the VS Code plugin")?;
|
||||||
cmd!("cmd.exe /c npm ci").run()?;
|
cmd!(sh, "cmd.exe /c npm ci").run()?;
|
||||||
|
|
||||||
cmd!("cmd.exe /c npm run package").run()?;
|
cmd!(sh, "cmd.exe /c npm run package").run()?;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Find the appropriate VS Code binary.
|
// Find the appropriate VS Code binary.
|
||||||
|
@ -104,9 +100,9 @@ fn install_client(client_opt: ClientOpt) -> Result<()> {
|
||||||
.copied()
|
.copied()
|
||||||
.find(|&bin| {
|
.find(|&bin| {
|
||||||
if cfg!(unix) {
|
if cfg!(unix) {
|
||||||
cmd!("{bin} --version").read().is_ok()
|
cmd!(sh, "{bin} --version").read().is_ok()
|
||||||
} else {
|
} else {
|
||||||
cmd!("cmd.exe /c {bin}.cmd --version").read().is_ok()
|
cmd!(sh, "cmd.exe /c {bin}.cmd --version").read().is_ok()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
|
@ -115,11 +111,11 @@ fn install_client(client_opt: ClientOpt) -> Result<()> {
|
||||||
|
|
||||||
// Install & verify.
|
// Install & verify.
|
||||||
let installed_extensions = if cfg!(unix) {
|
let installed_extensions = if cfg!(unix) {
|
||||||
cmd!("{code} --install-extension rust-analyzer.vsix --force").run()?;
|
cmd!(sh, "{code} --install-extension rust-analyzer.vsix --force").run()?;
|
||||||
cmd!("{code} --list-extensions").read()?
|
cmd!(sh, "{code} --list-extensions").read()?
|
||||||
} else {
|
} else {
|
||||||
cmd!("cmd.exe /c {code}.cmd --install-extension rust-analyzer.vsix --force").run()?;
|
cmd!(sh, "cmd.exe /c {code}.cmd --install-extension rust-analyzer.vsix --force").run()?;
|
||||||
cmd!("cmd.exe /c {code}.cmd --list-extensions").read()?
|
cmd!(sh, "cmd.exe /c {code}.cmd --list-extensions").read()?
|
||||||
};
|
};
|
||||||
|
|
||||||
if !installed_extensions.contains("rust-analyzer") {
|
if !installed_extensions.contains("rust-analyzer") {
|
||||||
|
@ -133,14 +129,14 @@ fn install_client(client_opt: ClientOpt) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install_server(opts: ServerOpt) -> Result<()> {
|
fn install_server(sh: &Shell, opts: ServerOpt) -> Result<()> {
|
||||||
let features = match opts.malloc {
|
let features = match opts.malloc {
|
||||||
Malloc::System => &[][..],
|
Malloc::System => &[][..],
|
||||||
Malloc::Mimalloc => &["--features", "mimalloc"],
|
Malloc::Mimalloc => &["--features", "mimalloc"],
|
||||||
Malloc::Jemalloc => &["--features", "jemalloc"],
|
Malloc::Jemalloc => &["--features", "jemalloc"],
|
||||||
};
|
};
|
||||||
|
|
||||||
let cmd = cmd!("cargo install --path crates/rust-analyzer --locked --force --features force-always-assert {features...}");
|
let cmd = cmd!(sh, "cargo install --path crates/rust-analyzer --locked --force --features force-always-assert {features...}");
|
||||||
cmd.run()?;
|
cmd.run()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,15 +14,16 @@ mod release;
|
||||||
mod dist;
|
mod dist;
|
||||||
mod metrics;
|
mod metrics;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::bail;
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
use xshell::{cmd, cp, pushd, pushenv};
|
use xshell::{cmd, Shell};
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
let _d = pushd(project_root())?;
|
let sh = &Shell::new()?;
|
||||||
|
sh.change_dir(project_root());
|
||||||
|
|
||||||
let flags = flags::Xtask::from_env()?;
|
let flags = flags::Xtask::from_env()?;
|
||||||
match flags.subcommand {
|
match flags.subcommand {
|
||||||
|
@ -30,18 +31,21 @@ fn main() -> Result<()> {
|
||||||
println!("{}", flags::Xtask::HELP);
|
println!("{}", flags::Xtask::HELP);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
flags::XtaskCmd::Install(cmd) => cmd.run(),
|
flags::XtaskCmd::Install(cmd) => cmd.run(sh),
|
||||||
flags::XtaskCmd::FuzzTests(_) => run_fuzzer(),
|
flags::XtaskCmd::FuzzTests(_) => run_fuzzer(sh),
|
||||||
flags::XtaskCmd::Release(cmd) => cmd.run(),
|
flags::XtaskCmd::Release(cmd) => cmd.run(sh),
|
||||||
flags::XtaskCmd::Promote(cmd) => cmd.run(),
|
flags::XtaskCmd::Promote(cmd) => cmd.run(sh),
|
||||||
flags::XtaskCmd::Dist(cmd) => cmd.run(),
|
flags::XtaskCmd::Dist(cmd) => cmd.run(sh),
|
||||||
flags::XtaskCmd::Metrics(cmd) => cmd.run(),
|
flags::XtaskCmd::Metrics(cmd) => cmd.run(sh),
|
||||||
flags::XtaskCmd::Bb(cmd) => {
|
flags::XtaskCmd::Bb(cmd) => {
|
||||||
{
|
{
|
||||||
let _d = pushd("./crates/rust-analyzer")?;
|
let _d = sh.push_dir("./crates/rust-analyzer");
|
||||||
cmd!("cargo build --release --features jemalloc").run()?;
|
cmd!(sh, "cargo build --release --features jemalloc").run()?;
|
||||||
}
|
}
|
||||||
cp("./target/release/rust-analyzer", format!("./target/rust-analyzer-{}", cmd.suffix))?;
|
sh.copy_file(
|
||||||
|
"./target/release/rust-analyzer",
|
||||||
|
format!("./target/rust-analyzer-{}", cmd.suffix),
|
||||||
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,25 +61,25 @@ fn project_root() -> PathBuf {
|
||||||
.to_path_buf()
|
.to_path_buf()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_fuzzer() -> Result<()> {
|
fn run_fuzzer(sh: &Shell) -> anyhow::Result<()> {
|
||||||
let _d = pushd("./crates/syntax")?;
|
let _d = sh.push_dir("./crates/syntax");
|
||||||
let _e = pushenv("RUSTUP_TOOLCHAIN", "nightly");
|
let _e = sh.push_env("RUSTUP_TOOLCHAIN", "nightly");
|
||||||
if cmd!("cargo fuzz --help").read().is_err() {
|
if cmd!(sh, "cargo fuzz --help").read().is_err() {
|
||||||
cmd!("cargo install cargo-fuzz").run()?;
|
cmd!(sh, "cargo install cargo-fuzz").run()?;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Expecting nightly rustc
|
// Expecting nightly rustc
|
||||||
let out = cmd!("rustc --version").read()?;
|
let out = cmd!(sh, "rustc --version").read()?;
|
||||||
if !out.contains("nightly") {
|
if !out.contains("nightly") {
|
||||||
bail!("fuzz tests require nightly rustc")
|
bail!("fuzz tests require nightly rustc")
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd!("cargo fuzz run parser").run()?;
|
cmd!(sh, "cargo fuzz run parser").run()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn date_iso() -> Result<String> {
|
fn date_iso(sh: &Shell) -> anyhow::Result<String> {
|
||||||
let res = cmd!("date -u +%Y-%m-%d").read()?;
|
let res = cmd!(sh, "date -u +%Y-%m-%d").read()?;
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,95 +1,103 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
env,
|
env, fs,
|
||||||
io::Write as _,
|
io::Write as _,
|
||||||
path::Path,
|
path::Path,
|
||||||
time::{Instant, SystemTime, UNIX_EPOCH},
|
time::{Instant, SystemTime, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{bail, format_err, Result};
|
use anyhow::{bail, format_err};
|
||||||
use xshell::{cmd, mkdir_p, pushd, pushenv, read_file, rm_rf};
|
use xshell::{cmd, Shell};
|
||||||
|
|
||||||
use crate::flags;
|
use crate::flags;
|
||||||
|
|
||||||
type Unit = String;
|
type Unit = String;
|
||||||
|
|
||||||
impl flags::Metrics {
|
impl flags::Metrics {
|
||||||
pub(crate) fn run(self) -> Result<()> {
|
pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
|
||||||
let mut metrics = Metrics::new()?;
|
let mut metrics = Metrics::new(sh)?;
|
||||||
if !self.dry_run {
|
if !self.dry_run {
|
||||||
rm_rf("./target/release")?;
|
sh.remove_path("./target/release")?;
|
||||||
}
|
}
|
||||||
if !Path::new("./target/rustc-perf").exists() {
|
if !Path::new("./target/rustc-perf").exists() {
|
||||||
mkdir_p("./target/rustc-perf")?;
|
sh.create_dir("./target/rustc-perf")?;
|
||||||
cmd!("git clone https://github.com/rust-lang/rustc-perf.git ./target/rustc-perf")
|
cmd!(sh, "git clone https://github.com/rust-lang/rustc-perf.git ./target/rustc-perf")
|
||||||
.run()?;
|
.run()?;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let _d = pushd("./target/rustc-perf")?;
|
let _d = sh.push_dir("./target/rustc-perf");
|
||||||
let revision = &metrics.perf_revision;
|
let revision = &metrics.perf_revision;
|
||||||
cmd!("git reset --hard {revision}").run()?;
|
cmd!(sh, "git reset --hard {revision}").run()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let _env = pushenv("RA_METRICS", "1");
|
let _env = sh.push_env("RA_METRICS", "1");
|
||||||
|
|
||||||
{
|
{
|
||||||
// https://github.com/rust-analyzer/rust-analyzer/issues/9997
|
// https://github.com/rust-analyzer/rust-analyzer/issues/9997
|
||||||
let _d = pushd("target/rustc-perf/collector/benchmarks/webrender")?;
|
let _d = sh.push_dir("target/rustc-perf/collector/benchmarks/webrender");
|
||||||
cmd!("cargo update -p url --precise 1.6.1").run()?;
|
cmd!(sh, "cargo update -p url --precise 1.6.1").run()?;
|
||||||
}
|
}
|
||||||
metrics.measure_build()?;
|
metrics.measure_build(sh)?;
|
||||||
metrics.measure_analysis_stats_self()?;
|
metrics.measure_analysis_stats_self(sh)?;
|
||||||
metrics.measure_analysis_stats("ripgrep")?;
|
metrics.measure_analysis_stats(sh, "ripgrep")?;
|
||||||
metrics.measure_analysis_stats("webrender")?;
|
metrics.measure_analysis_stats(sh, "webrender")?;
|
||||||
metrics.measure_analysis_stats("diesel/diesel")?;
|
metrics.measure_analysis_stats(sh, "diesel/diesel")?;
|
||||||
|
|
||||||
if !self.dry_run {
|
if !self.dry_run {
|
||||||
let _d = pushd("target")?;
|
let _d = sh.push_dir("target");
|
||||||
let metrics_token = env::var("METRICS_TOKEN").unwrap();
|
let metrics_token = env::var("METRICS_TOKEN").unwrap();
|
||||||
cmd!(
|
cmd!(
|
||||||
|
sh,
|
||||||
"git clone --depth 1 https://{metrics_token}@github.com/rust-analyzer/metrics.git"
|
"git clone --depth 1 https://{metrics_token}@github.com/rust-analyzer/metrics.git"
|
||||||
)
|
)
|
||||||
.run()?;
|
.run()?;
|
||||||
let _d = pushd("metrics")?;
|
let _d = sh.push_dir("metrics");
|
||||||
|
|
||||||
let mut file = std::fs::OpenOptions::new().append(true).open("metrics.json")?;
|
let mut file = fs::File::options().append(true).open("metrics.json")?;
|
||||||
writeln!(file, "{}", metrics.json())?;
|
writeln!(file, "{}", metrics.json())?;
|
||||||
cmd!("git add .").run()?;
|
cmd!(sh, "git add .").run()?;
|
||||||
cmd!("git -c user.name=Bot -c user.email=dummy@example.com commit --message 📈")
|
cmd!(sh, "git -c user.name=Bot -c user.email=dummy@example.com commit --message 📈")
|
||||||
.run()?;
|
.run()?;
|
||||||
cmd!("git push origin master").run()?;
|
cmd!(sh, "git push origin master").run()?;
|
||||||
}
|
}
|
||||||
eprintln!("{:#?}", metrics);
|
eprintln!("{metrics:#?}");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Metrics {
|
impl Metrics {
|
||||||
fn measure_build(&mut self) -> Result<()> {
|
fn measure_build(&mut self, sh: &Shell) -> anyhow::Result<()> {
|
||||||
eprintln!("\nMeasuring build");
|
eprintln!("\nMeasuring build");
|
||||||
cmd!("cargo fetch").run()?;
|
cmd!(sh, "cargo fetch").run()?;
|
||||||
|
|
||||||
let time = Instant::now();
|
let time = Instant::now();
|
||||||
cmd!("cargo build --release --package rust-analyzer --bin rust-analyzer").run()?;
|
cmd!(sh, "cargo build --release --package rust-analyzer --bin rust-analyzer").run()?;
|
||||||
let time = time.elapsed();
|
let time = time.elapsed();
|
||||||
self.report("build", time.as_millis() as u64, "ms".into());
|
self.report("build", time.as_millis() as u64, "ms".into());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn measure_analysis_stats_self(&mut self) -> Result<()> {
|
fn measure_analysis_stats_self(&mut self, sh: &Shell) -> anyhow::Result<()> {
|
||||||
self.measure_analysis_stats_path("self", ".")
|
self.measure_analysis_stats_path(sh, "self", ".")
|
||||||
}
|
}
|
||||||
fn measure_analysis_stats(&mut self, bench: &str) -> Result<()> {
|
fn measure_analysis_stats(&mut self, sh: &Shell, bench: &str) -> anyhow::Result<()> {
|
||||||
self.measure_analysis_stats_path(
|
self.measure_analysis_stats_path(
|
||||||
|
sh,
|
||||||
bench,
|
bench,
|
||||||
&format!("./target/rustc-perf/collector/benchmarks/{}", bench),
|
&format!("./target/rustc-perf/collector/benchmarks/{}", bench),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn measure_analysis_stats_path(&mut self, name: &str, path: &str) -> Result<()> {
|
fn measure_analysis_stats_path(
|
||||||
eprintln!("\nMeasuring analysis-stats/{}", name);
|
&mut self,
|
||||||
let output = cmd!("./target/release/rust-analyzer -q analysis-stats --memory-usage {path}")
|
sh: &Shell,
|
||||||
.read()?;
|
name: &str,
|
||||||
|
path: &str,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
eprintln!("\nMeasuring analysis-stats/{name}");
|
||||||
|
let output =
|
||||||
|
cmd!(sh, "./target/release/rust-analyzer -q analysis-stats --memory-usage {path}")
|
||||||
|
.read()?;
|
||||||
for (metric, value, unit) in parse_metrics(&output) {
|
for (metric, value, unit) in parse_metrics(&output) {
|
||||||
self.report(&format!("analysis-stats/{}/{}", name, metric), value, unit.into());
|
self.report(&format!("analysis-stats/{name}/{metric}"), value, unit.into());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -125,10 +133,10 @@ struct Host {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Metrics {
|
impl Metrics {
|
||||||
fn new() -> Result<Metrics> {
|
fn new(sh: &Shell) -> anyhow::Result<Metrics> {
|
||||||
let host = Host::new()?;
|
let host = Host::new(sh)?;
|
||||||
let timestamp = SystemTime::now();
|
let timestamp = SystemTime::now();
|
||||||
let revision = cmd!("git rev-parse HEAD").read()?;
|
let revision = cmd!(sh, "git rev-parse HEAD").read()?;
|
||||||
let perf_revision = "c52ee623e231e7690a93be88d943016968c1036b".into();
|
let perf_revision = "c52ee623e231e7690a93be88d943016968c1036b".into();
|
||||||
Ok(Metrics { host, timestamp, revision, perf_revision, metrics: BTreeMap::new() })
|
Ok(Metrics { host, timestamp, revision, perf_revision, metrics: BTreeMap::new() })
|
||||||
}
|
}
|
||||||
|
@ -157,28 +165,29 @@ impl Metrics {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Host {
|
impl Host {
|
||||||
fn new() -> Result<Host> {
|
fn new(sh: &Shell) -> anyhow::Result<Host> {
|
||||||
if cfg!(not(target_os = "linux")) {
|
if cfg!(not(target_os = "linux")) {
|
||||||
bail!("can only collect metrics on Linux ");
|
bail!("can only collect metrics on Linux ");
|
||||||
}
|
}
|
||||||
|
|
||||||
let os = read_field("/etc/os-release", "PRETTY_NAME=")?.trim_matches('"').to_string();
|
let os = read_field(sh, "/etc/os-release", "PRETTY_NAME=")?.trim_matches('"').to_string();
|
||||||
|
|
||||||
let cpu =
|
let cpu = read_field(sh, "/proc/cpuinfo", "model name")?
|
||||||
read_field("/proc/cpuinfo", "model name")?.trim_start_matches(':').trim().to_string();
|
.trim_start_matches(':')
|
||||||
|
.trim()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
let mem = read_field("/proc/meminfo", "MemTotal:")?;
|
let mem = read_field(sh, "/proc/meminfo", "MemTotal:")?;
|
||||||
|
|
||||||
return Ok(Host { os, cpu, mem });
|
return Ok(Host { os, cpu, mem });
|
||||||
|
|
||||||
fn read_field(path: &str, field: &str) -> Result<String> {
|
fn read_field(sh: &Shell, path: &str, field: &str) -> anyhow::Result<String> {
|
||||||
let text = read_file(path)?;
|
let text = sh.read_file(path)?;
|
||||||
|
|
||||||
let line = text
|
text.lines()
|
||||||
.lines()
|
.find_map(|it| it.strip_prefix(field))
|
||||||
.find(|it| it.starts_with(field))
|
.map(|it| it.trim().to_string())
|
||||||
.ok_or_else(|| format_err!("can't parse {}", path))?;
|
.ok_or_else(|| format_err!("can't parse {}", path))
|
||||||
Ok(line[field.len()..].trim().to_string())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn to_json(&self, mut obj: write_json::Object<'_>) {
|
fn to_json(&self, mut obj: write_json::Object<'_>) {
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
mod changelog;
|
mod changelog;
|
||||||
|
|
||||||
use xshell::{cmd, pushd, read_dir, read_file, write_file};
|
use xshell::{cmd, Shell};
|
||||||
|
|
||||||
use crate::{date_iso, flags, is_release_tag, project_root, Result};
|
use crate::{date_iso, flags, is_release_tag, project_root};
|
||||||
|
|
||||||
impl flags::Release {
|
impl flags::Release {
|
||||||
pub(crate) fn run(self) -> Result<()> {
|
pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
|
||||||
if !self.dry_run {
|
if !self.dry_run {
|
||||||
cmd!("git switch release").run()?;
|
cmd!(sh, "git switch release").run()?;
|
||||||
cmd!("git fetch upstream --tags --force").run()?;
|
cmd!(sh, "git fetch upstream --tags --force").run()?;
|
||||||
cmd!("git reset --hard tags/nightly").run()?;
|
cmd!(sh, "git reset --hard tags/nightly").run()?;
|
||||||
// The `release` branch sometimes has a couple of cherry-picked
|
// The `release` branch sometimes has a couple of cherry-picked
|
||||||
// commits for patch releases. If that's the case, just overwrite
|
// commits for patch releases. If that's the case, just overwrite
|
||||||
// it. As we are setting `release` branch to an up-to-date `nightly`
|
// it. As we are setting `release` branch to an up-to-date `nightly`
|
||||||
|
@ -19,24 +19,24 @@ impl flags::Release {
|
||||||
// commits -- they'll be kept alive by the tag. More generally, we
|
// commits -- they'll be kept alive by the tag. More generally, we
|
||||||
// don't care about historic releases all that much, it's fine even
|
// don't care about historic releases all that much, it's fine even
|
||||||
// to delete old tags.
|
// to delete old tags.
|
||||||
cmd!("git push --force").run()?;
|
cmd!(sh, "git push --force").run()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates bits of manual.adoc.
|
// Generates bits of manual.adoc.
|
||||||
cmd!("cargo test -p ide_assists -p ide_diagnostics -p rust-analyzer -- sourcegen_")
|
cmd!(sh, "cargo test -p ide_assists -p ide_diagnostics -p rust-analyzer -- sourcegen_")
|
||||||
.run()?;
|
.run()?;
|
||||||
|
|
||||||
let website_root = project_root().join("../rust-analyzer.github.io");
|
let website_root = project_root().join("../rust-analyzer.github.io");
|
||||||
{
|
{
|
||||||
let _dir = pushd(&website_root)?;
|
let _dir = sh.push_dir(&website_root);
|
||||||
cmd!("git switch src").run()?;
|
cmd!(sh, "git switch src").run()?;
|
||||||
cmd!("git pull").run()?;
|
cmd!(sh, "git pull").run()?;
|
||||||
}
|
}
|
||||||
let changelog_dir = website_root.join("./thisweek/_posts");
|
let changelog_dir = website_root.join("./thisweek/_posts");
|
||||||
|
|
||||||
let today = date_iso()?;
|
let today = date_iso(sh)?;
|
||||||
let commit = cmd!("git rev-parse HEAD").read()?;
|
let commit = cmd!(sh, "git rev-parse HEAD").read()?;
|
||||||
let changelog_n = read_dir(changelog_dir.as_path())?.len();
|
let changelog_n = sh.read_dir(changelog_dir.as_path())?.len();
|
||||||
|
|
||||||
for adoc in [
|
for adoc in [
|
||||||
"manual.adoc",
|
"manual.adoc",
|
||||||
|
@ -48,42 +48,46 @@ impl flags::Release {
|
||||||
let src = project_root().join("./docs/user/").join(adoc);
|
let src = project_root().join("./docs/user/").join(adoc);
|
||||||
let dst = website_root.join(adoc);
|
let dst = website_root.join(adoc);
|
||||||
|
|
||||||
let contents = read_file(src)?;
|
let contents = sh.read_file(src)?;
|
||||||
write_file(dst, contents)?;
|
sh.write_file(dst, contents)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let tags = cmd!("git tag --list").read()?;
|
let tags = cmd!(sh, "git tag --list").read()?;
|
||||||
let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap();
|
let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap();
|
||||||
|
|
||||||
let contents = changelog::get_changelog(changelog_n, &commit, prev_tag, &today)?;
|
let contents = changelog::get_changelog(sh, changelog_n, &commit, prev_tag, &today)?;
|
||||||
let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n));
|
let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n));
|
||||||
write_file(&path, &contents)?;
|
sh.write_file(&path, &contents)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl flags::Promote {
|
impl flags::Promote {
|
||||||
pub(crate) fn run(self) -> Result<()> {
|
pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
|
||||||
let _dir = pushd("../rust-rust-analyzer")?;
|
let _dir = sh.push_dir("../rust-rust-analyzer");
|
||||||
cmd!("git switch master").run()?;
|
cmd!(sh, "git switch master").run()?;
|
||||||
cmd!("git fetch upstream").run()?;
|
cmd!(sh, "git fetch upstream").run()?;
|
||||||
cmd!("git reset --hard upstream/master").run()?;
|
cmd!(sh, "git reset --hard upstream/master").run()?;
|
||||||
cmd!("git submodule update --recursive").run()?;
|
cmd!(sh, "git submodule update --recursive").run()?;
|
||||||
|
|
||||||
let branch = format!("rust-analyzer-{}", date_iso()?);
|
let date = date_iso(sh)?;
|
||||||
cmd!("git switch -c {branch}").run()?;
|
let branch = format!("rust-analyzer-{date}");
|
||||||
|
cmd!(sh, "git switch -c {branch}").run()?;
|
||||||
{
|
{
|
||||||
let _dir = pushd("src/tools/rust-analyzer")?;
|
let _dir = sh.push_dir("src/tools/rust-analyzer");
|
||||||
cmd!("git fetch origin").run()?;
|
cmd!(sh, "git fetch origin").run()?;
|
||||||
cmd!("git reset --hard origin/release").run()?;
|
cmd!(sh, "git reset --hard origin/release").run()?;
|
||||||
}
|
}
|
||||||
cmd!("git add src/tools/rust-analyzer").run()?;
|
cmd!(sh, "git add src/tools/rust-analyzer").run()?;
|
||||||
cmd!("git commit -m':arrow_up: rust-analyzer'").run()?;
|
cmd!(sh, "git commit -m':arrow_up: rust-analyzer'").run()?;
|
||||||
if !self.dry_run {
|
if !self.dry_run {
|
||||||
cmd!("git push -u origin {branch}").run()?;
|
cmd!(sh, "git push -u origin {branch}").run()?;
|
||||||
cmd!("xdg-open https://github.com/matklad/rust/pull/new/{branch}?body=r%3F%20%40ghost")
|
cmd!(
|
||||||
.run()?;
|
sh,
|
||||||
|
"xdg-open https://github.com/matklad/rust/pull/new/{branch}?body=r%3F%20%40ghost"
|
||||||
|
)
|
||||||
|
.run()?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::{env, iter};
|
use std::{env, iter};
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::bail;
|
||||||
use xshell::cmd;
|
use xshell::{cmd, Shell};
|
||||||
|
|
||||||
pub(crate) fn get_changelog(
|
pub(crate) fn get_changelog(
|
||||||
|
sh: &Shell,
|
||||||
changelog_n: usize,
|
changelog_n: usize,
|
||||||
commit: &str,
|
commit: &str,
|
||||||
prev_tag: &str,
|
prev_tag: &str,
|
||||||
today: &str,
|
today: &str,
|
||||||
) -> Result<String> {
|
) -> anyhow::Result<String> {
|
||||||
let git_log = cmd!("git log {prev_tag}..HEAD --merges --reverse").read()?;
|
let git_log = cmd!(sh, "git log {prev_tag}..HEAD --merges --reverse").read()?;
|
||||||
let mut features = String::new();
|
let mut features = String::new();
|
||||||
let mut fixes = String::new();
|
let mut fixes = String::new();
|
||||||
let mut internal = String::new();
|
let mut internal = String::new();
|
||||||
|
@ -30,14 +31,15 @@ pub(crate) fn get_changelog(
|
||||||
|
|
||||||
// we don't use an HTTPS client or JSON parser to keep the build times low
|
// we don't use an HTTPS client or JSON parser to keep the build times low
|
||||||
let pr_json =
|
let pr_json =
|
||||||
cmd!("curl -s -H {accept} -H {authorization} {pr_url}/{pr}").read()?;
|
cmd!(sh, "curl -s -H {accept} -H {authorization} {pr_url}/{pr}").read()?;
|
||||||
let pr_title = cmd!("jq .title").stdin(&pr_json).read()?;
|
let pr_title = cmd!(sh, "jq .title").stdin(&pr_json).read()?;
|
||||||
let pr_title = unescape(&pr_title[1..pr_title.len() - 1]);
|
let pr_title = unescape(&pr_title[1..pr_title.len() - 1]);
|
||||||
let pr_comment = cmd!("jq .body").stdin(pr_json).read()?;
|
let pr_comment = cmd!(sh, "jq .body").stdin(pr_json).read()?;
|
||||||
|
|
||||||
let comments_json =
|
let comments_json =
|
||||||
cmd!("curl -s -H {accept} -H {authorization} {pr_url}/{pr}/comments").read()?;
|
cmd!(sh, "curl -s -H {accept} -H {authorization} {pr_url}/{pr}/comments")
|
||||||
let pr_comments = cmd!("jq .[].body").stdin(comments_json).read()?;
|
.read()?;
|
||||||
|
let pr_comments = cmd!(sh, "jq .[].body").stdin(comments_json).read()?;
|
||||||
|
|
||||||
let l = iter::once(pr_comment.as_str())
|
let l = iter::once(pr_comment.as_str())
|
||||||
.chain(pr_comments.lines())
|
.chain(pr_comments.lines())
|
||||||
|
|
Loading…
Reference in a new issue