Simplify xtask

lib/bin/test separation isn't really needed.
This commit is contained in:
Aleksey Kladov 2021-03-01 20:16:23 +03:00
parent c17f2bf2a2
commit d9dcfd81c5
17 changed files with 167 additions and 180 deletions

View file

@ -6,9 +6,6 @@ authors = ["rust-analyzer developers"]
publish = false
license = "MIT OR Apache-2.0"
[lib]
doctest = false
[dependencies]
anyhow = "1.0.26"
flate2 = "1.0"

View file

@ -20,7 +20,7 @@
use crate::{ensure_rustfmt, project_root, Result};
pub use self::{
pub(crate) use self::{
gen_assists_docs::{generate_assists_docs, generate_assists_tests},
gen_diagnostic_docs::generate_diagnostic_docs,
gen_feature_docs::generate_feature_docs,
@ -30,17 +30,17 @@
};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Mode {
pub(crate) enum Mode {
Overwrite,
Verify,
}
pub struct CodegenCmd {
pub features: bool,
pub(crate) struct CodegenCmd {
pub(crate) features: bool,
}
impl CodegenCmd {
pub fn run(self) -> Result<()> {
pub(crate) fn run(self) -> Result<()> {
if self.features {
generate_lint_completions(Mode::Overwrite)?;
}

View file

@ -7,12 +7,12 @@
project_root, rust_files_in, Result,
};
pub fn generate_assists_tests(mode: Mode) -> Result<()> {
pub(crate) fn generate_assists_tests(mode: Mode) -> Result<()> {
let assists = Assist::collect()?;
generate_tests(&assists, mode)
}
pub fn generate_assists_docs(mode: Mode) -> Result<()> {
pub(crate) fn generate_assists_docs(mode: Mode) -> Result<()> {
let assists = Assist::collect()?;
let contents = assists.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n");
let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim());

View file

@ -7,7 +7,7 @@
project_root, rust_files, Result,
};
pub fn generate_diagnostic_docs(mode: Mode) -> Result<()> {
pub(crate) fn generate_diagnostic_docs(mode: Mode) -> Result<()> {
let diagnostics = Diagnostic::collect()?;
let contents =
diagnostics.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n");

View file

@ -7,7 +7,7 @@
project_root, rust_files, Result,
};
pub fn generate_feature_docs(mode: Mode) -> Result<()> {
pub(crate) fn generate_feature_docs(mode: Mode) -> Result<()> {
let features = Feature::collect()?;
let contents = features.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n");
let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim());

View file

@ -10,7 +10,7 @@
run_rustfmt,
};
pub fn generate_lint_completions(mode: Mode) -> Result<()> {
pub(crate) fn generate_lint_completions(mode: Mode) -> Result<()> {
if !Path::new("./target/rust").exists() {
cmd!("git clone --depth=1 https://github.com/rust-lang/rust ./target/rust").run()?;
}

View file

@ -12,7 +12,7 @@
project_root, Result,
};
pub fn generate_parser_tests(mode: Mode) -> Result<()> {
pub(crate) fn generate_parser_tests(mode: Mode) -> Result<()> {
let tests = tests_from_dir(&project_root().join(Path::new("crates/parser/src/grammar")))?;
fn install_tests(tests: &HashMap<String, Test>, into: &str, mode: Mode) -> Result<()> {
let tests_dir = project_root().join(into);

View file

@ -18,7 +18,7 @@
project_root, Result,
};
pub fn generate_syntax(mode: Mode) -> Result<()> {
pub(crate) fn generate_syntax(mode: Mode) -> Result<()> {
let grammar = rust_grammar();
let ast = lower(&grammar);

View file

@ -11,13 +11,13 @@
use crate::{date_iso, project_root};
pub struct DistCmd {
pub nightly: bool,
pub client_version: Option<String>,
pub(crate) struct DistCmd {
pub(crate) nightly: bool,
pub(crate) client_version: Option<String>,
}
impl DistCmd {
pub fn run(self) -> Result<()> {
pub(crate) fn run(self) -> Result<()> {
let dist = project_root().join("dist");
rm_rf(&dist)?;
mkdir_p(&dist)?;

View file

@ -8,13 +8,13 @@
// Latest stable, feel free to send a PR if this lags behind.
const REQUIRED_RUST_VERSION: u32 = 50;
pub struct InstallCmd {
pub client: Option<ClientOpt>,
pub server: Option<ServerOpt>,
pub(crate) struct InstallCmd {
pub(crate) client: Option<ClientOpt>,
pub(crate) server: Option<ServerOpt>,
}
#[derive(Clone, Copy)]
pub enum ClientOpt {
pub(crate) enum ClientOpt {
VsCode,
VsCodeExploration,
VsCodeInsiders,
@ -24,7 +24,7 @@ pub enum ClientOpt {
}
impl ClientOpt {
pub const fn as_cmds(&self) -> &'static [&'static str] {
pub(crate) const fn as_cmds(&self) -> &'static [&'static str] {
match self {
ClientOpt::VsCode => &["code"],
ClientOpt::VsCodeExploration => &["code-exploration"],
@ -60,18 +60,18 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
}
}
pub struct ServerOpt {
pub malloc: Malloc,
pub(crate) struct ServerOpt {
pub(crate) malloc: Malloc,
}
pub enum Malloc {
pub(crate) enum Malloc {
System,
Mimalloc,
Jemalloc,
}
impl InstallCmd {
pub fn run(self) -> Result<()> {
pub(crate) fn run(self) -> Result<()> {
if cfg!(target_os = "macos") {
fix_path_for_mac().context("Fix path for mac")?
}

View file

@ -1,131 +0,0 @@
//! Support library for `cargo xtask` command.
//!
//! See https://github.com/matklad/cargo-xtask/
pub mod codegen;
mod ast_src;
pub mod install;
pub mod release;
pub mod dist;
pub mod pre_commit;
pub mod metrics;
pub mod pre_cache;
use std::{
env,
path::{Path, PathBuf},
};
use walkdir::{DirEntry, WalkDir};
use xshell::{cmd, pushd, pushenv};
use crate::codegen::Mode;
pub use anyhow::{bail, Context as _, Result};
pub fn project_root() -> PathBuf {
Path::new(
&env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
)
.ancestors()
.nth(1)
.unwrap()
.to_path_buf()
}
pub fn rust_files() -> impl Iterator<Item = PathBuf> {
rust_files_in(&project_root().join("crates"))
}
pub fn cargo_files() -> impl Iterator<Item = PathBuf> {
files_in(&project_root(), "toml")
.filter(|path| path.file_name().map(|it| it == "Cargo.toml").unwrap_or(false))
}
pub fn rust_files_in(path: &Path) -> impl Iterator<Item = PathBuf> {
files_in(path, "rs")
}
pub fn run_rustfmt(mode: Mode) -> Result<()> {
let _dir = pushd(project_root())?;
let _e = pushenv("RUSTUP_TOOLCHAIN", "stable");
ensure_rustfmt()?;
let check = match mode {
Mode::Overwrite => &[][..],
Mode::Verify => &["--", "--check"],
};
cmd!("cargo fmt {check...}").run()?;
Ok(())
}
fn ensure_rustfmt() -> Result<()> {
let out = cmd!("rustfmt --version").read()?;
if !out.contains("stable") {
bail!(
"Failed to run rustfmt from toolchain 'stable'. \
Please run `rustup component add rustfmt --toolchain stable` to install it.",
)
}
Ok(())
}
pub fn run_clippy() -> Result<()> {
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 = "
-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 _e = pushenv("RUSTUP_TOOLCHAIN", "nightly");
if cmd!("cargo fuzz --help").read().is_err() {
cmd!("cargo install cargo-fuzz").run()?;
};
// Expecting nightly rustc
let out = cmd!("rustc --version").read()?;
if !out.contains("nightly") {
bail!("fuzz tests require nightly rustc")
}
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())
}
fn files_in(path: &Path, ext: &'static str) -> impl Iterator<Item = PathBuf> {
let iter = WalkDir::new(path);
return iter
.into_iter()
.filter_entry(|e| !is_hidden(e))
.map(|e| e.unwrap())
.filter(|e| !e.file_type().is_dir())
.map(|e| e.into_path())
.filter(move |path| path.extension().map(|it| it == ext).unwrap_or(false));
fn is_hidden(entry: &DirEntry) -> bool {
entry.file_name().to_str().map(|s| s.starts_with('.')).unwrap_or(false)
}
}

View file

@ -7,22 +7,35 @@
//!
//! This binary is integrated into the `cargo` command line by using an alias in
//! `.cargo/config`.
mod codegen;
mod ast_src;
#[cfg(test)]
mod tidy;
use std::env;
mod install;
mod release;
mod dist;
mod pre_commit;
mod metrics;
mod pre_cache;
use anyhow::bail;
use anyhow::{bail, Result};
use codegen::CodegenCmd;
use pico_args::Arguments;
use xshell::{cmd, cp, pushd};
use xtask::{
codegen::{self, Mode},
use std::{
env,
path::{Path, PathBuf},
};
use walkdir::{DirEntry, WalkDir};
use xshell::{cmd, cp, pushd, pushenv};
use crate::{
codegen::Mode,
dist::DistCmd,
install::{InstallCmd, Malloc, ServerOpt},
metrics::MetricsCmd,
pre_cache::PreCacheCmd,
pre_commit, project_root,
release::{PromoteCmd, ReleaseCmd},
run_clippy, run_fuzzer, run_rustfmt, Result,
};
fn main() -> Result<()> {
@ -172,3 +185,110 @@ fn finish_args(args: Arguments) -> Result<()> {
}
Ok(())
}
fn project_root() -> PathBuf {
Path::new(
&env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
)
.ancestors()
.nth(1)
.unwrap()
.to_path_buf()
}
fn rust_files() -> impl Iterator<Item = PathBuf> {
rust_files_in(&project_root().join("crates"))
}
#[cfg(test)]
fn cargo_files() -> impl Iterator<Item = PathBuf> {
files_in(&project_root(), "toml")
.filter(|path| path.file_name().map(|it| it == "Cargo.toml").unwrap_or(false))
}
fn rust_files_in(path: &Path) -> impl Iterator<Item = PathBuf> {
files_in(path, "rs")
}
fn run_rustfmt(mode: Mode) -> Result<()> {
let _dir = pushd(project_root())?;
let _e = pushenv("RUSTUP_TOOLCHAIN", "stable");
ensure_rustfmt()?;
let check = match mode {
Mode::Overwrite => &[][..],
Mode::Verify => &["--", "--check"],
};
cmd!("cargo fmt {check...}").run()?;
Ok(())
}
fn ensure_rustfmt() -> Result<()> {
let out = cmd!("rustfmt --version").read()?;
if !out.contains("stable") {
bail!(
"Failed to run rustfmt from toolchain 'stable'. \
Please run `rustup component add rustfmt --toolchain stable` to install it.",
)
}
Ok(())
}
fn run_clippy() -> Result<()> {
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 = "
-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(())
}
fn run_fuzzer() -> Result<()> {
let _d = pushd("./crates/syntax")?;
let _e = pushenv("RUSTUP_TOOLCHAIN", "nightly");
if cmd!("cargo fuzz --help").read().is_err() {
cmd!("cargo install cargo-fuzz").run()?;
};
// Expecting nightly rustc
let out = cmd!("rustc --version").read()?;
if !out.contains("nightly") {
bail!("fuzz tests require nightly rustc")
}
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())
}
fn files_in(path: &Path, ext: &'static str) -> impl Iterator<Item = PathBuf> {
let iter = WalkDir::new(path);
return iter
.into_iter()
.filter_entry(|e| !is_hidden(e))
.map(|e| e.unwrap())
.filter(|e| !e.file_type().is_dir())
.map(|e| e.into_path())
.filter(move |path| path.extension().map(|it| it == ext).unwrap_or(false));
fn is_hidden(entry: &DirEntry) -> bool {
entry.file_name().to_str().map(|s| s.starts_with('.')).unwrap_or(false)
}
}

View file

@ -11,12 +11,12 @@
type Unit = String;
pub struct MetricsCmd {
pub dry_run: bool,
pub(crate) struct MetricsCmd {
pub(crate) dry_run: bool,
}
impl MetricsCmd {
pub fn run(self) -> Result<()> {
pub(crate) fn run(self) -> Result<()> {
let mut metrics = Metrics::new()?;
if !self.dry_run {
rm_rf("./target/release")?;

View file

@ -6,12 +6,12 @@
use anyhow::Result;
use xshell::rm_rf;
pub struct PreCacheCmd;
pub(crate) struct PreCacheCmd;
impl PreCacheCmd {
/// Cleans the `./target` dir after the build such that only
/// dependencies are cached on CI.
pub fn run(self) -> Result<()> {
pub(crate) fn run(self) -> Result<()> {
let slow_tests_cookie = Path::new("./target/.slow_tests_cookie");
if !slow_tests_cookie.exists() {
panic!("slow tests were skipped on CI!")

View file

@ -9,7 +9,7 @@
// FIXME: if there are changed `.ts` files, also reformat TypeScript (by
// shelling out to `npm fmt`).
pub fn run_hook() -> Result<()> {
pub(crate) fn run_hook() -> Result<()> {
run_rustfmt(Mode::Overwrite)?;
let diff = cmd!("git diff --diff-filter=MAR --name-only --cached").read()?;
@ -23,7 +23,7 @@ pub fn run_hook() -> Result<()> {
Ok(())
}
pub fn install_hook() -> Result<()> {
pub(crate) fn install_hook() -> Result<()> {
let hook_path: PathBuf =
format!("./.git/hooks/pre-commit{}", std::env::consts::EXE_SUFFIX).into();

View file

@ -4,12 +4,12 @@
use crate::{codegen, date_iso, is_release_tag, project_root, Mode, Result};
pub struct ReleaseCmd {
pub dry_run: bool,
pub(crate) struct ReleaseCmd {
pub(crate) dry_run: bool,
}
impl ReleaseCmd {
pub fn run(self) -> Result<()> {
pub(crate) fn run(self) -> Result<()> {
if !self.dry_run {
cmd!("git switch release").run()?;
cmd!("git fetch upstream --tags --force").run()?;
@ -86,12 +86,12 @@ pub fn run(self) -> Result<()> {
}
}
pub struct PromoteCmd {
pub dry_run: bool,
pub(crate) struct PromoteCmd {
pub(crate) dry_run: bool,
}
impl PromoteCmd {
pub fn run(self) -> Result<()> {
pub(crate) fn run(self) -> Result<()> {
let _dir = pushd("../rust-rust-analyzer")?;
cmd!("git switch master").run()?;
cmd!("git fetch upstream").run()?;

View file

@ -4,7 +4,8 @@
};
use xshell::{cmd, read_file};
use xtask::{
use crate::{
cargo_files,
codegen::{self, Mode},
project_root, run_rustfmt, rust_files,