Switch from not_bash to xshell

This commit is contained in:
Aleksey Kladov 2020-10-16 19:46:03 +02:00
parent f0412da4a2
commit 49a90d4c31
14 changed files with 181 additions and 325 deletions

23
Cargo.lock generated
View file

@ -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",
]

View file

@ -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

View file

@ -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<String> {
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();
<text.as_bytes()
)?;
let rustfmt_toml = project_root().join("rustfmt.toml");
let stdout = cmd!("rustfmt --config-path {rustfmt_toml} --config fn_single_line=true")
.stdin(text)
.read()?;
Ok(format!("//! {}\n\n{}\n", PREAMBLE, stdout))
}

View file

@ -3,15 +3,13 @@ use std::path::{Path, PathBuf};
use quote::quote;
use walkdir::WalkDir;
use xshell::{cmd, read_file};
use crate::{
codegen::{project_root, reformat, update, Mode, Result},
not_bash::{fs2, run},
};
use crate::codegen::{project_root, reformat, update, Mode, Result};
pub fn generate_features(mode: Mode) -> 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<String> {
.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 } }
});

View file

@ -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<PathBuf>) -> Result<Patch> {
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();
}
}

View file

@ -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 {

View file

@ -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<Item = PathBuf> {
}
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<String> {
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())
}

View file

@ -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();

View file

@ -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<Metrics> {
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<String> {
let text = fs2::read_to_string(path)?;
let text = read_file(path)?;
let line = text
.lines()

View file

@ -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<PathBuf>) -> 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<Path>) -> 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<String> {
run_process_inner(&cmd, echo, stdin).with_context(|| format!("process `{}` failed", cmd))
}
pub fn date_iso() -> Result<String> {
run!("date --iso --utc")
}
fn run_process_inner(cmd: &str, echo: bool, stdin: Option<&[u8]>) -> Result<String> {
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<String> {
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<PathBuf>,
pushenv_stack: Vec<(OsString, Option<OsString>)>,
}
impl Env {
fn with<F: FnOnce(&mut Env) -> T, T>(f: F) -> T {
thread_local! {
static ENV: RefCell<Env> = 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()
}
}

View file

@ -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()

View file

@ -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(())

View file

@ -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(())
}

View file

@ -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::<Vec<_>>();
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::<Vec<_>>();
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);
}