| // 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())), | |
| } | |
| } | |
| } |