From 49a90d4c31148a6533d9ee9a288f42b454b2f421 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 16 Oct 2020 19:46:03 +0200 Subject: Switch from not_bash to xshell --- Cargo.lock | 23 ++++-- xtask/Cargo.toml | 2 +- xtask/src/codegen.rs | 19 ++--- xtask/src/codegen/gen_features.rs | 10 +-- xtask/src/dist.rs | 33 ++++---- xtask/src/install.rs | 46 ++++++----- xtask/src/lib.rs | 52 ++++++------ xtask/src/main.rs | 4 +- xtask/src/metrics.rs | 39 +++++---- xtask/src/not_bash.rs | 169 -------------------------------------- xtask/src/pre_cache.rs | 5 +- xtask/src/pre_commit.rs | 8 +- xtask/src/release.rs | 60 +++++++------- xtask/tests/tidy.rs | 36 ++++++-- 14 files changed, 181 insertions(+), 325 deletions(-) delete mode 100644 xtask/src/not_bash.rs diff --git a/Cargo.lock b/Cargo.lock index d470d84f2..7a77ed722 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -421,12 +421,6 @@ dependencies = [ "toolchain", ] -[[package]] -name = "fs-err" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcd1163ae48bda72a20ae26d66a04d3094135cadab911cff418ae5e33f253431" - [[package]] name = "fsevent" version = "2.0.2" @@ -1920,17 +1914,32 @@ dependencies = [ "winapi-build", ] +[[package]] +name = "xshell" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f7f756f2faab73adb00db44db716598ab2c9e4bce4a875c053022291bd3cab4" +dependencies = [ + "xshell-macros", +] + +[[package]] +name = "xshell-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b020c2f3132b34067e2f6ebc58f0f210624898713a8186b8cdb75d3b8c3001" + [[package]] name = "xtask" version = "0.1.0" dependencies = [ "anyhow", "flate2", - "fs-err", "pico-args", "proc-macro2", "quote", "ungrammar", "walkdir", "write-json", + "xshell", ] diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 01a838825..2ef956485 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -18,5 +18,5 @@ quote = "1.0.2" ungrammar = "1.1.3" walkdir = "2.3.1" write-json = "0.1.0" -fs-err = "2.3" +xshell = "0.1" # Avoid adding more dependencies to this crate diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs index 1e7894617..3ee4c1adf 100644 --- a/xtask/src/codegen.rs +++ b/xtask/src/codegen.rs @@ -15,12 +15,9 @@ use std::{ fmt, mem, path::{Path, PathBuf}, }; +use xshell::{cmd, pushenv, read_file, write_file}; -use crate::{ - ensure_rustfmt, - not_bash::{fs2, pushenv, run}, - project_root, Result, -}; +use crate::{ensure_rustfmt, project_root, Result}; pub use self::{ gen_assists_docs::{generate_assists_docs, generate_assists_tests}, @@ -57,7 +54,7 @@ impl CodegenCmd { /// A helper to update file on disk if it has changed. /// With verify = false, fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { - match fs2::read_to_string(path) { + match read_file(path) { Ok(old_contents) if normalize(&old_contents) == normalize(contents) => { return Ok(()); } @@ -67,7 +64,7 @@ fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { anyhow::bail!("`{}` is not up-to-date", path.display()); } eprintln!("updating {}", path.display()); - fs2::write(path, contents)?; + write_file(path, contents)?; return Ok(()); fn normalize(s: &str) -> String { @@ -80,10 +77,10 @@ const PREAMBLE: &str = "Generated file, do not edit by hand, see `xtask/src/code fn reformat(text: &str) -> Result { let _e = pushenv("RUSTUP_TOOLCHAIN", "stable"); ensure_rustfmt()?; - let stdout = run!( - "rustfmt --config-path {} --config fn_single_line=true", project_root().join("rustfmt.toml").display(); - Result<()> { if !Path::new("./target/rust").exists() { - run!("git clone https://github.com/rust-lang/rust ./target/rust")?; + cmd!("git clone https://github.com/rust-lang/rust ./target/rust").run()?; } let contents = generate_descriptor("./target/rust/src/doc/unstable-book/src".into())?; @@ -34,7 +32,7 @@ fn generate_descriptor(src_dir: PathBuf) -> Result { .map(|entry| { let path = entry.path(); let feature_ident = path.file_stem().unwrap().to_str().unwrap().replace("-", "_"); - let doc = fs2::read_to_string(path).unwrap(); + let doc = read_file(path).unwrap(); quote! { LintCompletion { label: #feature_ident, description: #doc } } }); diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs index aa7d94967..9e15a5a4c 100644 --- a/xtask/src/dist.rs +++ b/xtask/src/dist.rs @@ -1,4 +1,3 @@ -use flate2::{write::GzEncoder, Compression}; use std::{ env, fs::File, @@ -7,11 +6,10 @@ use std::{ }; use anyhow::Result; +use flate2::{write::GzEncoder, Compression}; +use xshell::{cmd, cp, mkdir_p, pushd, read_file, rm_rf, write_file}; -use crate::{ - not_bash::{date_iso, fs2, pushd, rm_rf, run}, - project_root, -}; +use crate::{date_iso, project_root}; pub struct DistCmd { pub nightly: bool, @@ -22,7 +20,7 @@ impl DistCmd { pub fn run(self) -> Result<()> { let dist = project_root().join("dist"); rm_rf(&dist)?; - fs2::create_dir_all(&dist)?; + mkdir_p(&dist)?; if let Some(version) = self.client_version { let release_tag = if self.nightly { "nightly".to_string() } else { date_iso()? }; @@ -34,7 +32,7 @@ impl DistCmd { } fn dist_client(version: &str, release_tag: &str) -> Result<()> { - let _d = pushd("./editors/code"); + let _d = pushd("./editors/code")?; let nightly = release_tag == "nightly"; let mut patch = Patch::new("./package.json")?; @@ -54,20 +52,16 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> { } patch.commit()?; - run!("npm ci")?; - run!("npx vsce package -o ../../dist/rust-analyzer.vsix")?; + cmd!("npm ci").run()?; + cmd!("npx vsce package -o ../../dist/rust-analyzer.vsix").run()?; Ok(()) } fn dist_server() -> Result<()> { if cfg!(target_os = "linux") { env::set_var("CC", "clang"); - run!( - "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release" - )?; - } else { - run!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release")?; } + cmd!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release").run()?; let (src, dst) = if cfg!(target_os = "linux") { ("./target/release/rust-analyzer", "./dist/rust-analyzer-linux") @@ -82,7 +76,7 @@ fn dist_server() -> Result<()> { let src = Path::new(src); let dst = Path::new(dst); - fs2::copy(&src, &dst)?; + cp(&src, &dst)?; gzip(&src, &dst.with_extension("gz"))?; Ok(()) @@ -105,7 +99,7 @@ struct Patch { impl Patch { fn new(path: impl Into) -> Result { let path = path.into(); - let contents = fs2::read_to_string(&path)?; + let contents = read_file(&path)?; Ok(Patch { path, original_contents: contents.clone(), contents }) } @@ -115,13 +109,14 @@ impl Patch { self } - fn commit(&self) -> io::Result<()> { - fs2::write(&self.path, &self.contents) + fn commit(&self) -> Result<()> { + write_file(&self.path, &self.contents)?; + Ok(()) } } impl Drop for Patch { fn drop(&mut self) { - fs2::write(&self.path, &self.original_contents).unwrap(); + write_file(&self.path, &self.original_contents).unwrap(); } } diff --git a/xtask/src/install.rs b/xtask/src/install.rs index fcc4f05e4..789e9f27b 100644 --- a/xtask/src/install.rs +++ b/xtask/src/install.rs @@ -3,8 +3,7 @@ use std::{env, path::PathBuf, str}; use anyhow::{bail, format_err, Context, Result}; - -use crate::not_bash::{pushd, run}; +use xshell::{cmd, pushd}; // Latest stable, feel free to send a PR if this lags behind. const REQUIRED_RUST_VERSION: u32 = 47; @@ -76,7 +75,7 @@ fn fix_path_for_mac() -> Result<()> { } fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> { - let _dir = pushd("./editors/code"); + let _dir = pushd("./editors/code")?; let find_code = |f: fn(&str) -> bool| -> Result<&'static str> { ["code", "code-insiders", "codium", "code-oss"] @@ -89,24 +88,25 @@ fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> { }; let installed_extensions = if cfg!(unix) { - run!("npm --version").context("`npm` is required to build the VS Code plugin")?; - run!("npm install")?; + cmd!("npm --version").run().context("`npm` is required to build the VS Code plugin")?; + cmd!("npm install").run()?; - run!("npm run package --scripts-prepend-node-path")?; + cmd!("npm run package --scripts-prepend-node-path").run()?; - let code = find_code(|bin| run!("{} --version", bin).is_ok())?; - run!("{} --install-extension rust-analyzer.vsix --force", code)?; - run!("{} --list-extensions", code; echo = false)? + let code = find_code(|bin| cmd!("{bin} --version").read().is_ok())?; + cmd!("{code} --install-extension rust-analyzer.vsix --force").run()?; + cmd!("{code} --list-extensions").read()? } else { - run!("cmd.exe /c npm --version") + cmd!("cmd.exe /c npm --version") + .run() .context("`npm` is required to build the VS Code plugin")?; - run!("cmd.exe /c npm install")?; + cmd!("cmd.exe /c npm install").run()?; - run!("cmd.exe /c npm run package")?; + cmd!("cmd.exe /c npm run package").run()?; - let code = find_code(|bin| run!("cmd.exe /c {}.cmd --version", bin).is_ok())?; - run!(r"cmd.exe /c {}.cmd --install-extension rust-analyzer.vsix --force", code)?; - run!("cmd.exe /c {}.cmd --list-extensions", code; echo = false)? + let code = find_code(|bin| cmd!("cmd.exe /c {bin}.cmd --version").read().is_ok())?; + cmd!("cmd.exe /c {code}.cmd --install-extension rust-analyzer.vsix --force").run()?; + cmd!("cmd.exe /c {code}.cmd --list-extensions").read()? }; if !installed_extensions.contains("rust-analyzer") { @@ -122,7 +122,7 @@ fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> { fn install_server(opts: ServerOpt) -> Result<()> { let mut old_rust = false; - if let Ok(stdout) = run!("cargo --version") { + if let Ok(stdout) = cmd!("cargo --version").read() { if !check_version(&stdout, REQUIRED_RUST_VERSION) { old_rust = true; } @@ -134,12 +134,13 @@ fn install_server(opts: ServerOpt) -> Result<()> { REQUIRED_RUST_VERSION, ) } - - let malloc_feature = match opts.malloc { - Malloc::System => "", - Malloc::Mimalloc => "--features mimalloc", + let features = match opts.malloc { + Malloc::System => &[][..], + Malloc::Mimalloc => &["--features", "mimalloc"], }; - let res = run!("cargo install --path crates/rust-analyzer --locked --force {}", malloc_feature); + + let cmd = cmd!("cargo install --path crates/rust-analyzer --locked --force {features...}"); + let res = cmd.run(); if res.is_err() && old_rust { eprintln!( @@ -148,7 +149,8 @@ fn install_server(opts: ServerOpt) -> Result<()> { ); } - res.map(drop) + res?; + Ok(()) } fn check_version(version_output: &str, min_minor_version: u32) -> bool { diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index e790d995f..babec2dbd 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs @@ -2,7 +2,6 @@ //! //! See https://github.com/matklad/cargo-xtask/ -pub mod not_bash; pub mod codegen; mod ast_src; @@ -19,11 +18,9 @@ use std::{ }; use walkdir::{DirEntry, WalkDir}; +use xshell::{cmd, pushd, pushenv}; -use crate::{ - codegen::Mode, - not_bash::{pushd, pushenv}, -}; +use crate::codegen::Mode; pub use anyhow::{bail, Context as _, Result}; @@ -53,18 +50,19 @@ pub fn rust_files(path: &Path) -> impl Iterator { } pub fn run_rustfmt(mode: Mode) -> Result<()> { - let _dir = pushd(project_root()); + let _dir = pushd(project_root())?; let _e = pushenv("RUSTUP_TOOLCHAIN", "stable"); ensure_rustfmt()?; - match mode { - Mode::Overwrite => run!("cargo fmt"), - Mode::Verify => run!("cargo fmt -- --check"), - }?; + let check = match mode { + Mode::Overwrite => &[][..], + Mode::Verify => &["--", "--check"], + }; + cmd!("cargo fmt {check...}").run()?; Ok(()) } fn ensure_rustfmt() -> Result<()> { - let out = run!("rustfmt --version")?; + let out = cmd!("rustfmt --version").read()?; if !out.contains("stable") { bail!( "Failed to run rustfmt from toolchain 'stable'. \ @@ -75,40 +73,46 @@ fn ensure_rustfmt() -> Result<()> { } pub fn run_clippy() -> Result<()> { - if run!("cargo clippy --version").is_err() { + if cmd!("cargo clippy --version").read().is_err() { bail!( "Failed run cargo clippy. \ Please run `rustup component add clippy` to install it.", ) } - let allowed_lints = [ - "clippy::collapsible_if", - "clippy::needless_pass_by_value", - "clippy::nonminimal_bool", - "clippy::redundant_pattern_matching", - ]; - run!("cargo clippy --all-features --all-targets -- -A {}", allowed_lints.join(" -A "))?; + let allowed_lints = " + -A clippy::collapsible_if + -A clippy::needless_pass_by_value + -A clippy::nonminimal_bool + -A clippy::redundant_pattern_matching + " + .split_ascii_whitespace(); + cmd!("cargo clippy --all-features --all-targets -- {allowed_lints...}").run()?; Ok(()) } pub fn run_fuzzer() -> Result<()> { - let _d = pushd("./crates/syntax"); + let _d = pushd("./crates/syntax")?; let _e = pushenv("RUSTUP_TOOLCHAIN", "nightly"); - if run!("cargo fuzz --help").is_err() { - run!("cargo install cargo-fuzz")?; + if cmd!("cargo fuzz --help").read().is_err() { + cmd!("cargo install cargo-fuzz").run()?; }; // Expecting nightly rustc - let out = run!("rustc --version")?; + let out = cmd!("rustc --version").read()?; if !out.contains("nightly") { bail!("fuzz tests require nightly rustc") } - run!("cargo fuzz run parser")?; + cmd!("cargo fuzz run parser").run()?; Ok(()) } +fn date_iso() -> Result { + let res = cmd!("date --iso --utc").read()?; + Ok(res) +} + fn is_release_tag(tag: &str) -> bool { tag.len() == "2020-02-24".len() && tag.starts_with(|c: char| c.is_ascii_digit()) } diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 3f4aa5497..97e5dcd4e 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -12,12 +12,12 @@ use std::env; use codegen::CodegenCmd; use pico_args::Arguments; +use xshell::pushd; use xtask::{ codegen::{self, Mode}, dist::DistCmd, install::{ClientOpt, InstallCmd, Malloc, ServerOpt}, metrics::MetricsCmd, - not_bash::pushd, pre_cache::PreCacheCmd, pre_commit, project_root, release::{PromoteCmd, ReleaseCmd}, @@ -29,7 +29,7 @@ fn main() -> Result<()> { return pre_commit::run_hook(); } - let _d = pushd(project_root()); + let _d = pushd(project_root())?; let mut args = Arguments::from_env(); let subcommand = args.subcommand()?.unwrap_or_default(); diff --git a/xtask/src/metrics.rs b/xtask/src/metrics.rs index 4bade2c7e..e0d1aaf97 100644 --- a/xtask/src/metrics.rs +++ b/xtask/src/metrics.rs @@ -7,8 +7,7 @@ use std::{ }; use anyhow::{bail, format_err, Result}; - -use crate::not_bash::{fs2, pushd, pushenv, rm_rf, run}; +use xshell::{cmd, mkdir_p, pushd, pushenv, read_file, rm_rf}; type Unit = String; @@ -23,12 +22,13 @@ impl MetricsCmd { rm_rf("./target/release")?; } if !Path::new("./target/rustc-perf").exists() { - fs2::create_dir_all("./target/rustc-perf")?; - run!("git clone https://github.com/rust-lang/rustc-perf.git ./target/rustc-perf")?; + mkdir_p("./target/rustc-perf")?; + cmd!("git clone https://github.com/rust-lang/rustc-perf.git ./target/rustc-perf") + .run()?; } { - let _d = pushd("./target/rustc-perf"); - run!("git reset --hard 1d9288b0da7febf2599917da1b57dc241a1af033")?; + let _d = pushd("./target/rustc-perf")?; + cmd!("git reset --hard 1d9288b0da7febf2599917da1b57dc241a1af033").run()?; } let _env = pushenv("RA_METRICS", "1"); @@ -39,17 +39,20 @@ impl MetricsCmd { metrics.measure_analysis_stats("webrender")?; if !self.dry_run { - let _d = pushd("target"); + let _d = pushd("target")?; let metrics_token = env::var("METRICS_TOKEN").unwrap(); - let repo = format!("https://{}@github.com/rust-analyzer/metrics.git", metrics_token); - run!("git clone --depth 1 {}", repo)?; - let _d = pushd("metrics"); + cmd!( + "git clone --depth 1 https://{metrics_token}@github.com/rust-analyzer/metrics.git" + ) + .run()?; + let _d = pushd("metrics")?; let mut file = std::fs::OpenOptions::new().append(true).open("metrics.json")?; writeln!(file, "{}", metrics.json())?; - run!("git add .")?; - run!("git -c user.name=Bot -c user.email=dummy@example.com commit --message 📈")?; - run!("git push origin master")?; + cmd!("git add .").run()?; + cmd!("git -c user.name=Bot -c user.email=dummy@example.com commit --message 📈") + .run()?; + cmd!("git push origin master").run()?; } eprintln!("{:#?}", metrics); Ok(()) @@ -59,10 +62,10 @@ impl MetricsCmd { impl Metrics { fn measure_build(&mut self) -> Result<()> { eprintln!("\nMeasuring build"); - run!("cargo fetch")?; + cmd!("cargo fetch").run()?; let time = Instant::now(); - run!("cargo build --release --package rust-analyzer --bin rust-analyzer")?; + cmd!("cargo build --release --package rust-analyzer --bin rust-analyzer").run()?; let time = time.elapsed(); self.report("build", time.as_millis() as u64, "ms".into()); Ok(()) @@ -78,7 +81,7 @@ impl Metrics { } fn measure_analysis_stats_path(&mut self, name: &str, path: &str) -> Result<()> { eprintln!("\nMeasuring analysis-stats/{}", name); - let output = run!("./target/release/rust-analyzer analysis-stats --quiet {}", path)?; + let output = cmd!("./target/release/rust-analyzer analysis-stats --quiet {path}").read()?; for (metric, value, unit) in parse_metrics(&output) { self.report(&format!("analysis-stats/{}/{}", name, metric), value, unit.into()); } @@ -118,7 +121,7 @@ impl Metrics { fn new() -> Result { let host = Host::new()?; let timestamp = SystemTime::now(); - let revision = run!("git rev-parse HEAD")?; + let revision = cmd!("git rev-parse HEAD").read()?; Ok(Metrics { host, timestamp, revision, metrics: BTreeMap::new() }) } @@ -160,7 +163,7 @@ impl Host { return Ok(Host { os, cpu, mem }); fn read_field<'a>(path: &str, field: &str) -> Result { - let text = fs2::read_to_string(path)?; + let text = read_file(path)?; let line = text .lines() diff --git a/xtask/src/not_bash.rs b/xtask/src/not_bash.rs deleted file mode 100644 index 038898993..000000000 --- a/xtask/src/not_bash.rs +++ /dev/null @@ -1,169 +0,0 @@ -//! A bad shell -- small cross platform module for writing glue code - -use std::{ - cell::RefCell, - env, - ffi::OsString, - io::{self, Write}, - path::{Path, PathBuf}, - process::{Command, Stdio}, -}; - -use anyhow::{bail, Context, Result}; - -pub use fs_err as fs2; - -#[macro_export] -macro_rules! run { - ($($expr:expr),*) => { - run!($($expr),*; echo = true) - }; - ($($expr:expr),* ; echo = $echo:expr) => { - $crate::not_bash::run_process(format!($($expr),*), $echo, None) - }; - ($($expr:expr),* ; <$stdin:expr) => { - $crate::not_bash::run_process(format!($($expr),*), false, Some($stdin)) - }; -} -pub use crate::run; - -pub struct Pushd { - _p: (), -} - -pub fn pushd(path: impl Into) -> Pushd { - Env::with(|env| env.pushd(path.into())); - Pushd { _p: () } -} - -impl Drop for Pushd { - fn drop(&mut self) { - Env::with(|env| env.popd()) - } -} - -pub struct Pushenv { - _p: (), -} - -pub fn pushenv(var: &str, value: &str) -> Pushenv { - Env::with(|env| env.pushenv(var.into(), value.into())); - Pushenv { _p: () } -} - -impl Drop for Pushenv { - fn drop(&mut self) { - Env::with(|env| env.popenv()) - } -} - -pub fn rm_rf(path: impl AsRef) -> io::Result<()> { - let path = path.as_ref(); - if !path.exists() { - return Ok(()); - } - if path.is_file() { - fs2::remove_file(path) - } else { - fs2::remove_dir_all(path) - } -} - -#[doc(hidden)] -pub fn run_process(cmd: String, echo: bool, stdin: Option<&[u8]>) -> Result { - run_process_inner(&cmd, echo, stdin).with_context(|| format!("process `{}` failed", cmd)) -} - -pub fn date_iso() -> Result { - run!("date --iso --utc") -} - -fn run_process_inner(cmd: &str, echo: bool, stdin: Option<&[u8]>) -> Result { - let mut args = shelx(cmd); - let binary = args.remove(0); - let current_dir = Env::with(|it| it.cwd().to_path_buf()); - - if echo { - println!("> {}", cmd) - } - - let mut command = Command::new(binary); - command.args(args).current_dir(current_dir).stderr(Stdio::inherit()); - let output = match stdin { - None => command.stdin(Stdio::null()).output(), - Some(stdin) => { - command.stdin(Stdio::piped()).stdout(Stdio::piped()); - let mut process = command.spawn()?; - process.stdin.take().unwrap().write_all(stdin)?; - process.wait_with_output() - } - }?; - let stdout = String::from_utf8(output.stdout)?; - - if echo { - print!("{}", stdout) - } - - if !output.status.success() { - bail!("{}", output.status) - } - - Ok(stdout.trim().to_string()) -} - -// FIXME: some real shell lexing here -fn shelx(cmd: &str) -> Vec { - let mut res = Vec::new(); - for (string_piece, in_quotes) in cmd.split('\'').zip([false, true].iter().copied().cycle()) { - if in_quotes { - res.push(string_piece.to_string()) - } else { - if !string_piece.is_empty() { - res.extend(string_piece.split_ascii_whitespace().map(|it| it.to_string())) - } - } - } - res -} - -struct Env { - pushd_stack: Vec, - pushenv_stack: Vec<(OsString, Option)>, -} - -impl Env { - fn with T, T>(f: F) -> T { - thread_local! { - static ENV: RefCell = RefCell::new(Env { - pushd_stack: vec![env::current_dir().unwrap()], - pushenv_stack: vec![], - }); - } - ENV.with(|it| f(&mut *it.borrow_mut())) - } - - fn pushd(&mut self, dir: PathBuf) { - let dir = self.cwd().join(dir); - self.pushd_stack.push(dir); - env::set_current_dir(self.cwd()) - .unwrap_or_else(|err| panic!("Failed to set cwd to {}: {}", self.cwd().display(), err)); - } - fn popd(&mut self) { - self.pushd_stack.pop().unwrap(); - env::set_current_dir(self.cwd()).unwrap(); - } - fn pushenv(&mut self, var: OsString, value: OsString) { - self.pushenv_stack.push((var.clone(), env::var_os(&var))); - env::set_var(var, value) - } - fn popenv(&mut self) { - let (var, value) = self.pushenv_stack.pop().unwrap(); - match value { - None => env::remove_var(var), - Some(value) => env::set_var(var, value), - } - } - fn cwd(&self) -> &Path { - self.pushd_stack.last().unwrap() - } -} diff --git a/xtask/src/pre_cache.rs b/xtask/src/pre_cache.rs index 47ba6ba24..569f88f68 100644 --- a/xtask/src/pre_cache.rs +++ b/xtask/src/pre_cache.rs @@ -4,8 +4,7 @@ use std::{ }; use anyhow::Result; - -use crate::not_bash::{fs2, rm_rf}; +use xshell::rm_rf; pub struct PreCacheCmd; @@ -26,7 +25,7 @@ impl PreCacheCmd { } } - fs2::remove_file("./target/.rustc_info.json")?; + rm_rf("./target/.rustc_info.json")?; let to_delete = read_dir("./crates", FileType::is_dir)? .into_iter() diff --git a/xtask/src/pre_commit.rs b/xtask/src/pre_commit.rs index 056f34acf..8f2dbea19 100644 --- a/xtask/src/pre_commit.rs +++ b/xtask/src/pre_commit.rs @@ -3,19 +3,21 @@ use std::{fs, path::PathBuf}; use anyhow::{bail, Result}; +use xshell::cmd; -use crate::{not_bash::run, project_root, run_rustfmt, Mode}; +use crate::{project_root, run_rustfmt, Mode}; // FIXME: if there are changed `.ts` files, also reformat TypeScript (by // shelling out to `npm fmt`). pub fn run_hook() -> Result<()> { run_rustfmt(Mode::Overwrite)?; - let diff = run!("git diff --diff-filter=MAR --name-only --cached")?; + let diff = cmd!("git diff --diff-filter=MAR --name-only --cached").read()?; let root = project_root(); for line in diff.lines() { - run!("git update-index --add {}", root.join(line).display())?; + let file = root.join(line); + cmd!("git update-index --add {file}").run()?; } Ok(()) diff --git a/xtask/src/release.rs b/xtask/src/release.rs index 3aab29801..14fc1f0dd 100644 --- a/xtask/src/release.rs +++ b/xtask/src/release.rs @@ -1,8 +1,6 @@ -use crate::{ - codegen, is_release_tag, - not_bash::{date_iso, fs2, pushd, run}, - project_root, Mode, Result, -}; +use xshell::{cmd, cp, pushd, read_dir, write_file}; + +use crate::{codegen, date_iso, is_release_tag, project_root, Mode, Result}; pub struct ReleaseCmd { pub dry_run: bool, @@ -11,10 +9,10 @@ pub struct ReleaseCmd { impl ReleaseCmd { pub fn run(self) -> Result<()> { if !self.dry_run { - run!("git switch release")?; - run!("git fetch upstream --tags --force")?; - run!("git reset --hard tags/nightly")?; - run!("git push")?; + cmd!("git switch release").run()?; + cmd!("git fetch upstream --tags --force").run()?; + cmd!("git reset --hard tags/nightly").run()?; + cmd!("git push").run()?; } codegen::generate_assists_docs(Mode::Overwrite)?; codegen::generate_feature_docs(Mode::Overwrite)?; @@ -23,8 +21,8 @@ impl ReleaseCmd { let changelog_dir = website_root.join("./thisweek/_posts"); let today = date_iso()?; - let commit = run!("git rev-parse HEAD")?; - let changelog_n = fs2::read_dir(changelog_dir.as_path())?.count(); + let commit = cmd!("git rev-parse HEAD").read()?; + let changelog_n = read_dir(changelog_dir.as_path())?.len(); let contents = format!( "\ @@ -52,20 +50,20 @@ https://github.com/sponsors/rust-analyzer[GitHub Sponsors]. ); let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n)); - fs2::write(&path, &contents)?; + write_file(&path, &contents)?; for &adoc in ["manual.adoc", "generated_features.adoc", "generated_assists.adoc"].iter() { let src = project_root().join("./docs/user/").join(adoc); let dst = website_root.join(adoc); - fs2::copy(src, dst)?; + cp(src, dst)?; } - let tags = run!("git tag --list"; echo = false)?; + let tags = cmd!("git tag --list").read()?; let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap(); - let git_log = run!("git log {}..HEAD --merges --reverse", prev_tag; echo = false)?; + let git_log = cmd!("git log {prev_tag}..HEAD --merges --reverse").read()?; let git_log_dst = website_root.join("git.log"); - fs2::write(git_log_dst, &git_log)?; + write_file(git_log_dst, &git_log)?; Ok(()) } @@ -77,27 +75,25 @@ pub struct PromoteCmd { impl PromoteCmd { pub fn run(self) -> Result<()> { - let _dir = pushd("../rust-rust-analyzer"); - run!("git switch master")?; - run!("git fetch upstream")?; - run!("git reset --hard upstream/master")?; - run!("git submodule update --recursive")?; + let _dir = pushd("../rust-rust-analyzer")?; + cmd!("git switch master").run()?; + cmd!("git fetch upstream").run()?; + cmd!("git reset --hard upstream/master").run()?; + cmd!("git submodule update --recursive").run()?; let branch = format!("rust-analyzer-{}", date_iso()?); - run!("git switch -c {}", branch)?; + cmd!("git switch -c {branch}").run()?; { - let _dir = pushd("src/tools/rust-analyzer"); - run!("git fetch origin")?; - run!("git reset --hard origin/release")?; + let _dir = pushd("src/tools/rust-analyzer")?; + cmd!("git fetch origin").run()?; + cmd!("git reset --hard origin/release").run()?; } - run!("git add src/tools/rust-analyzer")?; - run!("git commit -m':arrow_up: rust-analyzer'")?; + cmd!("git add src/tools/rust-analyzer").run()?; + cmd!("git commit -m':arrow_up: rust-analyzer'").run()?; if !self.dry_run { - run!("git push")?; - run!( - "xdg-open https://github.com/matklad/rust/pull/new/{}?body=r%3F%20%40ghost", - branch - )?; + cmd!("git push").run()?; + cmd!("xdg-open https://github.com/matklad/rust/pull/new/{branch}?body=r%3F%20%40ghost") + .run()?; } Ok(()) } diff --git a/xtask/tests/tidy.rs b/xtask/tests/tidy.rs index b3bb9d543..d335adb72 100644 --- a/xtask/tests/tidy.rs +++ b/xtask/tests/tidy.rs @@ -3,9 +3,9 @@ use std::{ path::{Path, PathBuf}, }; +use xshell::{cmd, read_file}; use xtask::{ codegen::{self, Mode}, - not_bash::{fs2, run}, project_root, run_rustfmt, rust_files, }; @@ -48,14 +48,13 @@ fn smoke_test_docs_generation() { fn check_lsp_extensions_docs() { let expected_hash = { let lsp_ext_rs = - fs2::read_to_string(project_root().join("crates/rust-analyzer/src/lsp_ext.rs")) - .unwrap(); + read_file(project_root().join("crates/rust-analyzer/src/lsp_ext.rs")).unwrap(); stable_hash(lsp_ext_rs.as_str()) }; let actual_hash = { let lsp_extensions_md = - fs2::read_to_string(project_root().join("docs/dev/lsp-extensions.md")).unwrap(); + read_file(project_root().join("docs/dev/lsp-extensions.md")).unwrap(); let text = lsp_extensions_md .lines() .find_map(|line| line.strip_prefix("lsp_ext.rs hash:")) @@ -83,7 +82,7 @@ Please adjust docs/dev/lsp-extensions.md. fn rust_files_are_tidy() { let mut tidy_docs = TidyDocs::default(); for path in rust_files(&project_root().join("crates")) { - let text = fs2::read_to_string(&path).unwrap(); + let text = read_file(&path).unwrap(); check_todo(&path, &text); check_trailing_ws(&path, &text); deny_clippy(&path, &text); @@ -94,8 +93,10 @@ fn rust_files_are_tidy() { #[test] fn check_merge_commits() { - let stdout = run!("git rev-list --merges --invert-grep --author 'bors\\[bot\\]' HEAD~19.."; echo = false) - .unwrap(); + let stdout = + dbg!(cmd!("git rev-list --merges --invert-grep --author 'bors\\[bot\\]' HEAD~19..")) + .read() + .unwrap(); if !stdout.is_empty() { panic!( " @@ -168,7 +169,7 @@ Zlib OR Apache-2.0 OR MIT .filter(|it| !it.is_empty()) .collect::>(); - let meta = run!("cargo metadata --format-version 1"; echo = false).unwrap(); + let meta = cmd!("cargo metadata --format-version 1").read().unwrap(); let mut licenses = meta .split(|c| c == ',' || c == '{' || c == '}') .filter(|it| it.contains(r#""license""#)) @@ -177,6 +178,25 @@ Zlib OR Apache-2.0 OR MIT .collect::>(); licenses.sort(); licenses.dedup(); + if licenses != expected { + let mut diff = String::new(); + + diff += &format!("New Licenses:\n"); + for &l in licenses.iter() { + if !expected.contains(&l) { + diff += &format!(" {}\n", l) + } + } + + diff += &format!("\nMissing Licenses:\n"); + for &l in expected.iter() { + if !licenses.contains(&l) { + diff += &format!(" {}\n", l) + } + } + + panic!("different set of licenses!\n{}", diff); + } assert_eq!(licenses, expected); } -- cgit v1.2.3