blob: c714a1da3488f8d14fe6f9636655d7fb9a9e97a6 [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//! # DataFusion repository development tools
//!
//! ## Example
//!
//! Run the default CI test suite locally:
//!
//! ```sh
//! cargo xtask ci step test workspace
//! ```
//!
//! Implementing the command inside `xtask` can make it easier to maintain. For example,
//! the local test runs and CI runs can keep in sync.
//!
//! ## Mechanism
//!
//! `xtask` is an internal Rust binary in this workspace. The `cargo xtask` alias
//! builds and runs that binary, forwarding the remaining arguments to it.
//!
//! There is no external dependency required.
//!
//! ## Reference
//!
//! The [`xtask` convention](https://github.com/matklad/cargo-xtask) keeps project
//! automation in ordinary Rust code. It is used by projects such as
//! [rust-analyzer](https://github.com/rust-lang/rust-analyzer/tree/master/xtask).
//! Cargo uses the same pattern for several
//! [`xtask-*` maintenance commands](https://github.com/rust-lang/cargo/blob/master/.cargo/config.toml).
//!
//! # Supported Commands
//!
//! ## CI steps
//!
//! A CI step is one command used by DataFusion's CI that can also be run
//! locally. `--explain` prints the complete shell command without executing it.
//!
//! Use `cargo xtask ci step help` to list the available steps and
//! `cargo xtask ci step <step-name> help` for step-specific arguments.
//!
//! # Examples
//!
//! Show all available CI steps:
//!
//! ```sh
//! cargo xtask help
//! ```
//!
//! Show the arguments and examples for the `test` step:
//!
//! ```sh
//! cargo xtask ci step test help
//! ```
//!
//! Run the `cli` variant of the `test` step:
//!
//! ```sh
//! cargo xtask ci step test cli
//! ```
//!
//! Print that step's shell command without running it:
//!
//! ```sh
//! cargo xtask ci step test cli --explain
//! ```
mod ci_steps;
use std::env;
use std::path::PathBuf;
type Result<T> = std::result::Result<T, String>;
fn main() {
let args = env::args().skip(1).collect::<Vec<_>>();
let result = Xtask::new().and_then(|xtask| xtask.run(&args));
if let Err(error) = result {
eprintln!("error: {error}");
std::process::exit(1);
}
}
struct Xtask {
root: PathBuf,
}
impl Xtask {
fn new() -> Result<Self> {
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let root = manifest_dir
.parent()
.ok_or_else(|| {
format!(
"could not find workspace root from {}",
manifest_dir.display()
)
})?
.to_path_buf();
Ok(Self { root })
}
fn run(&self, args: &[String]) -> Result<()> {
match args {
[] => {
print!("{}", ci_steps::help());
Ok(())
}
[help_arg] if ci_steps::is_help_arg(help_arg) => {
print!("{}", ci_steps::help());
Ok(())
}
[ci, step, step_args @ ..] if ci == "ci" && step == "step" => {
ci_steps::run(&self.root, step_args)
}
_ => Err(format!("unknown command\n\n{}", ci_steps::help())),
}
}
}