Drop the xtask helper as it is superseded by Nox.

While the xtask code base is better engineered than our slightly messy Nox
manifest, all functionality is available via Nox including some that is not
available via xtask. Finally, only the Nox sessions are used in the CI by now so
that xtask does not see regular automated usage.
This commit is contained in:
Adam Reichold 2023-06-05 17:12:30 +02:00
parent f1b6cb9256
commit b816d4d561
14 changed files with 9 additions and 519 deletions

View File

@ -1,6 +1,3 @@
[alias]
xtask = "run --package xtask --"
[target.'cfg(feature = "cargo-clippy")']
rustflags = [
# Lints to enforce in CI
@ -11,6 +8,7 @@ rustflags = [
"-Dclippy::filter_map_next",
"-Dclippy::flat_map_option",
"-Dclippy::let_unit_value",
"-Dclippy::manual_assert",
"-Dclippy::manual_ok_or",
"-Dclippy::todo",
"-Dclippy::unnecessary_wraps",

View File

@ -53,7 +53,7 @@ mv target/guide netlify_build/main/
## Build public docs
cargo xtask doc
nox -s docs
mv target/doc netlify_build/main/doc/
echo "<meta http-equiv=refresh content=0;url=pyo3/>" > netlify_build/main/doc/index.html
@ -61,7 +61,7 @@ echo "<meta http-equiv=refresh content=0;url=pyo3/>" > netlify_build/main/doc/in
## Build internal docs
echo "<div class='internal-banner' style='position:fixed; z-index: 99999; color:red;border:3px solid red;margin-left: auto; margin-right: auto; width: 430px;left:0;right: 0;'><div style='display: flex; align-items: center; justify-content: center;'> ⚠️ Internal Docs ⚠️ Not Public API 👉 <a href='https://pyo3.rs/main/doc/pyo3/index.html' style='color:red;text-decoration:underline;'>Official Docs Here</a></div></div>" > netlify_build/banner.html
RUSTDOCFLAGS="--html-before-content netlify_build/banner.html" cargo xtask doc --internal
RUSTDOCFLAGS="--html-before-content netlify_build/banner.html" nox -s docs -- nightly internal
rm netlify_build/banner.html
mkdir -p netlify_build/internal

View File

@ -186,7 +186,6 @@ members = [
"pyo3-macros-backend",
"pytests",
"examples",
"xtask"
]
[package.metadata.docs.rs]

View File

@ -51,7 +51,7 @@ There are some specific areas of focus where help is currently needed for the do
You can build the docs (including all features) with
```shell
cargo xtask doc --open
nox -s docs -- open
```
#### Doctests
@ -95,8 +95,10 @@ Tests run with all supported Python versions with the latest stable Rust compile
If you are adding a new feature, you should add it to the `full` feature in our *Cargo.toml** so that it is tested in CI.
You can run these tests yourself with
```cargo xtask ci```
See [its documentation](https://github.com/PyO3/pyo3/tree/main/xtask#readme) for more commands you can run.
```nox```
and
```nox -l```
lists further commands you can run.
### Documenting changes
@ -145,7 +147,7 @@ You can view what code is and isn't covered by PyO3's tests. We aim to have 100%
- First, generate a `lcov.info` file with
```shell
cargo xtask coverage
nox -s coverage
```
You can install an IDE plugin to view the coverage. For example, if you use VSCode:
- Add the [coverage-gutters](https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters) plugin.

View File

@ -1,15 +0,0 @@
[package]
name = "xtask"
version = "0.1.0"
edition = "2018"
publish = false
[[bin]]
name = "xtask"
[dependencies]
anyhow = "1.0.51"
# Clap 3 requires MSRV 1.54
structopt = { version = "0.3", default-features = false }
clap = { version = "2" }

View File

@ -1,23 +0,0 @@
## Commands to test PyO3.
To run these commands, you should be in PyO3's root directory, and run (for example) `cargo xtask ci`.
```
USAGE:
xtask.exe <SUBCOMMAND>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
SUBCOMMANDS:
ci Runs everything
clippy Runs `clippy`, denying all warnings
coverage Runs `cargo llvm-cov` for the PyO3 codebase
default Only runs the fast things (this is used if no command is specified)
doc Attempts to render the documentation
fmt Checks Rust and Python code formatting with `rustfmt` and `black`
help Prints this message or the help of the given subcommand(s)
test Runs various variations on `cargo test`
test-py Runs the tests in examples/ and pytests/
```

View File

@ -1,216 +0,0 @@
use crate::utils::*;
use anyhow::{ensure, Result};
use std::io;
use std::process::{Command, Output};
use std::time::Instant;
use structopt::StructOpt;
pub const MSRV: &str = "1.56";
#[derive(StructOpt)]
pub enum Subcommand {
/// Only runs the fast things (this is used if no command is specified)
Default,
/// Runs everything
Ci,
/// Checks Rust and Python code formatting with `rustfmt` and `black`
Fmt,
/// Runs `clippy`, denying all warnings.
Clippy,
/// Attempts to render the documentation.
Doc(DocOpts),
/// Runs various variations on `cargo test`
Test,
/// Runs the tests in examples/ and pytests/
TestPy,
}
impl Default for Subcommand {
fn default() -> Self {
Self::Default
}
}
#[derive(StructOpt)]
pub struct DocOpts {
/// Whether to run the docs using nightly rustdoc
#[structopt(long)]
pub stable: bool,
/// Whether to open the docs after rendering.
#[structopt(long)]
pub open: bool,
/// Whether to show the private and hidden API.
#[structopt(long)]
pub internal: bool,
}
impl Default for DocOpts {
fn default() -> Self {
Self {
stable: true,
open: false,
internal: false,
}
}
}
impl Subcommand {
pub fn execute(self) -> Result<()> {
print_metadata()?;
let start = Instant::now();
match self {
Subcommand::Default => {
crate::fmt::rust::run()?;
crate::clippy::run()?;
crate::test::run()?;
crate::doc::run(DocOpts::default())?;
}
Subcommand::Ci => {
let installed = Installed::new()?;
crate::fmt::rust::run()?;
if installed.black {
crate::fmt::python::run()?;
} else {
Installed::warn_black()
};
crate::clippy::run()?;
crate::test::run()?;
crate::doc::run(DocOpts::default())?;
if installed.nox {
crate::pytests::run(None)?;
} else {
Installed::warn_nox()
};
installed.assert()?
}
Subcommand::Doc(opts) => crate::doc::run(opts)?,
Subcommand::Fmt => {
crate::fmt::rust::run()?;
crate::fmt::python::run()?;
}
Subcommand::Clippy => crate::clippy::run()?,
Subcommand::TestPy => crate::pytests::run(None)?,
Subcommand::Test => crate::test::run()?,
};
let dt = start.elapsed().as_secs();
let minutes = dt / 60;
let seconds = dt % 60;
println!("\nxtask finished in {}m {}s.", minutes, seconds);
Ok(())
}
}
/// Run a command as a child process, inheriting stdin, stdout and stderr.
pub fn run(command: &mut Command) -> Result<()> {
let command_str = format!("{:?}", command);
let github_actions = std::env::var_os("GITHUB_ACTIONS").is_some();
if github_actions {
println!("::group::Running: {}", command_str);
} else {
println!("Running: {}", command_str);
}
let status = command.spawn()?.wait()?;
ensure! {
status.success(),
"process did not run successfully ({exit}): {command}",
exit = match status.code() {
Some(code) => format!("exit code {}", code),
None => "terminated by signal".into(),
},
command = command_str,
};
if github_actions {
println!("::endgroup::")
}
Ok(())
}
/// Like `run`, but does not inherit stdin, stdout and stderr.
pub fn run_with_output(command: &mut Command) -> Result<Output> {
let command_str = format!("{:?}", command);
println!("Running: {}", command_str);
let output = command.output()?;
ensure! {
output.status.success(),
"process did not run successfully ({exit}): {command}:\n{stderr}",
exit = match output.status.code() {
Some(code) => format!("exit code {}", code),
None => "terminated by signal".into(),
},
command = command_str,
stderr = String::from_utf8_lossy(&output.stderr)
};
Ok(output)
}
#[derive(Copy, Clone, Debug)]
pub struct Installed {
pub nox: bool,
pub black: bool,
}
impl Installed {
pub fn new() -> anyhow::Result<Self> {
Ok(Self {
nox: Self::nox()?,
black: Self::black()?,
})
}
pub fn nox() -> anyhow::Result<bool> {
let output = std::process::Command::new("nox").arg("--version").output();
match output {
Ok(_) => Ok(true),
Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(false),
Err(other) => Err(other.into()),
}
}
pub fn warn_nox() {
eprintln!("Skipping: formatting Python code, because `nox` was not found");
}
pub fn black() -> anyhow::Result<bool> {
let output = std::process::Command::new("black")
.arg("--version")
.output();
match output {
Ok(_) => Ok(true),
Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(false),
Err(other) => Err(other.into()),
}
}
pub fn warn_black() {
eprintln!("Skipping: Python code formatting, because `black` was not found.");
}
pub fn assert(&self) -> anyhow::Result<()> {
if self.nox && self.black {
Ok(())
} else {
let mut err =
String::from("\n\nxtask was unable to run all tests due to some missing programs:");
if !self.black {
err.push_str("\n`black` was not installed. (`pip install black`)");
}
if !self.nox {
err.push_str("\n`nox` was not installed. (`pip install nox`)");
}
Err(anyhow::anyhow!(err))
}
}
}

View File

@ -1,25 +0,0 @@
use crate::cli;
use std::process::Command;
pub fn run() -> anyhow::Result<()> {
cli::run(
Command::new("cargo")
.arg("clippy")
.arg("--features=full")
.arg("--all-targets")
.arg("--workspace")
.arg("--")
.arg("-Dwarnings"),
)?;
cli::run(
Command::new("cargo")
.arg("clippy")
.arg("--all-targets")
.arg("--workspace")
.arg("--features=abi3,full")
.arg("--")
.arg("-Dwarnings"),
)?;
Ok(())
}

View File

@ -1,42 +0,0 @@
use crate::cli;
use crate::cli::DocOpts;
use std::process::Command;
//--cfg docsrs --Z unstable-options --document-hidden-items
pub fn run(opts: DocOpts) -> anyhow::Result<()> {
let mut flags = Vec::new();
if !opts.stable {
flags.push("--cfg docsrs");
}
if opts.internal {
flags.push("--Z unstable-options");
flags.push("--document-hidden-items");
}
flags.push("-Dwarnings");
std::env::set_var("RUSTDOCFLAGS", flags.join(" "));
cli::run(
Command::new(concat!(env!("CARGO_HOME"), "/bin/cargo"))
.args(if opts.stable { None } else { Some("+nightly") })
.arg("doc")
.arg("--lib")
.arg("--no-default-features")
.arg("--features=full")
.arg("--no-deps")
.arg("--workspace")
.args(if opts.internal {
&["--document-private-items"][..]
} else {
&["--exclude=pyo3-macros", "--exclude=pyo3-macros-backend"][..]
})
.args(if opts.stable {
&[][..]
} else {
&["-Z", "unstable-options", "-Z", "rustdoc-scrape-examples"][..]
})
.args(if opts.open { Some("--open") } else { None }),
)?;
Ok(())
}

View File

@ -1,23 +0,0 @@
pub mod rust {
use crate::cli;
use std::process::Command;
pub fn run() -> anyhow::Result<()> {
cli::run(
Command::new("cargo")
.arg("fmt")
.arg("--all")
.arg("--")
.arg("--check"),
)?;
Ok(())
}
}
pub mod python {
use crate::cli;
use std::process::Command;
pub fn run() -> anyhow::Result<()> {
cli::run(Command::new("black").arg(".").arg("--check"))?;
Ok(())
}
}

View File

@ -1,23 +0,0 @@
use clap::ErrorKind::MissingArgumentOrSubcommand;
use structopt::StructOpt;
pub mod cli;
pub mod clippy;
pub mod doc;
pub mod fmt;
pub mod pytests;
pub mod test;
pub mod utils;
fn main() -> anyhow::Result<()> {
// Avoid spewing backtraces all over the command line
// For some reason this is automatically enabled on nightly compilers...
std::env::set_var("RUST_LIB_BACKTRACE", "0");
match cli::Subcommand::from_args_safe() {
Ok(c) => c.execute()?,
Err(e) if e.kind == MissingArgumentOrSubcommand => cli::Subcommand::default().execute()?,
Err(e) => return Err(e.into()),
}
Ok(())
}

View File

@ -1,27 +0,0 @@
use crate::cli;
use anyhow::Result;
use std::{path::Path, process::Command};
pub fn run<'a>(env: impl IntoIterator<Item = (&'a String, &'a String)> + Copy) -> Result<()> {
cli::run(
Command::new("nox")
.arg("--non-interactive")
.arg("-f")
.arg(Path::new("pytests").join("noxfile.py"))
.envs(env),
)?;
for entry in std::fs::read_dir("examples")? {
let path = entry?.path();
if path.is_dir() && path.join("noxfile.py").exists() {
cli::run(
Command::new("nox")
.arg("--non-interactive")
.arg("-f")
.arg(path.join("noxfile.py"))
.envs(env),
)?;
}
}
Ok(())
}

View File

@ -1,81 +0,0 @@
use crate::cli::{self, MSRV};
use std::process::Command;
pub fn run() -> anyhow::Result<()> {
cli::run(
Command::new("cargo")
.arg("test")
.arg("--lib")
.arg("--no-default-features")
.arg("--tests")
.arg("--quiet"),
)?;
cli::run(
Command::new("cargo")
.arg("test")
.arg("--no-default-features")
.arg("--features=full")
.arg("--quiet"),
)?;
cli::run(
Command::new("cargo")
.arg("test")
.arg("--no-default-features")
.arg("--features=abi3,full")
.arg("--quiet"),
)?;
// If the MSRV toolchain is not installed, this will install it
cli::run(
Command::new("rustup")
.arg("toolchain")
.arg("install")
.arg(MSRV),
)?;
// Test MSRV
cli::run(
Command::new(concat!(env!("CARGO_HOME"), "/bin/cargo"))
.arg(format!("+{}", MSRV))
.arg("test")
.arg("--no-default-features")
.arg("--features=full,auto-initialize")
.arg("--quiet"),
)?;
// If the nightly toolchain is not installed, this will install it
cli::run(
Command::new("rustup")
.arg("toolchain")
.arg("install")
.arg("nightly"),
)?;
cli::run(
Command::new(concat!(env!("CARGO_HOME"), "/bin/cargo"))
.arg("+nightly")
.arg("test")
.arg("--no-default-features")
.arg("--features=full,nightly")
.arg("--quiet"),
)?;
cli::run(
Command::new("cargo")
.arg("test")
.arg("--manifest-path=pyo3-ffi/Cargo.toml")
.arg("--quiet"),
)?;
cli::run(
Command::new("cargo")
.arg("test")
.arg("--no-default-features")
.arg("--manifest-path=pyo3-build-config/Cargo.toml")
.arg("--quiet"),
)?;
Ok(())
}

View File

@ -1,34 +0,0 @@
use anyhow::ensure;
use std::process::Command;
pub fn get_output(command: &mut Command) -> anyhow::Result<std::process::Output> {
let output = command.output()?;
ensure! {
output.status.success(),
"process did not run successfully ({exit}): {command:?}",
exit = match output.status.code() {
Some(code) => format!("exit code {}", code),
None => "terminated by signal".into(),
},
command = command,
};
Ok(output)
}
pub fn print_metadata() -> anyhow::Result<()> {
let rustc_output = std::process::Command::new("rustc")
.arg("--version")
.arg("--verbose")
.output()?;
let rustc_version = core::str::from_utf8(&rustc_output.stdout).unwrap();
println!("Metadata: \n\n{}", rustc_version);
let py_output = std::process::Command::new("python")
.arg("--version")
.arg("-V")
.output()?;
let py_version = core::str::from_utf8(&py_output.stdout).unwrap();
println!("{}", py_version);
Ok(())
}