|  | // Copyright 2023 Google LLC | 
|  | // | 
|  | // Licensed 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. | 
|  |  | 
|  | //! Main build script for the betosync project, used for both local development and in CI. | 
|  | //! | 
|  | //! Usage: | 
|  | //! ```sh | 
|  | //! cargo run -p build_scripts -- run-default-checks | 
|  | //! ``` | 
|  |  | 
|  | #![allow(missing_docs)] | 
|  |  | 
|  | use clap::Parser as _; | 
|  | use cmd_runner::{ | 
|  | cargo_workspace::{CargoOptions, CargoWorkspaceSubcommand, FormatterOptions}, | 
|  | fuzzers::run_workspace_fuzz_targets, | 
|  | license_checker::LicenseSubcommand, | 
|  | }; | 
|  | use env_logger::Env; | 
|  | use license::LICENSE_CHECKER; | 
|  | use log::info; | 
|  | use std::{env, path}; | 
|  | use xshell::{cmd, Shell}; | 
|  |  | 
|  | mod license; | 
|  |  | 
|  | fn main() -> anyhow::Result<()> { | 
|  | env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); | 
|  | let cli: Cli = Cli::parse(); | 
|  |  | 
|  | let build_script_dir = path::PathBuf::from( | 
|  | env::var("CARGO_MANIFEST_DIR").expect("Must be run via Cargo to establish root directory"), | 
|  | ); | 
|  | let root_dir = build_script_dir | 
|  | .parent() | 
|  | .expect("Parent dir from build_script crate should exist"); | 
|  |  | 
|  | match cli.subcommand { | 
|  | Subcommand::RunDefaultChecks(ref check_options) => { | 
|  | run_default_checks(root_dir, check_options)?; | 
|  | print!(concat!( | 
|  | "Congratulations, the default checks passed. Since you like quality, here are\n", | 
|  | "some more checks you may like:\n", | 
|  | "    cargo run -p build_scripts -- run-rust-fuzzers\n", | 
|  | )); | 
|  | } | 
|  | Subcommand::VerifyCi { ref check_options } => verify_ci(root_dir, check_options)?, | 
|  | Subcommand::RunAllChecks { ref check_options } => run_all_checks(root_dir, check_options)?, | 
|  | Subcommand::CleanEverything => clean_everything(root_dir)?, | 
|  | Subcommand::CargoWorkspace(subcommand) => { | 
|  | let sh = xshell::Shell::new()?; | 
|  | sh.change_dir(root_dir); | 
|  | subcommand.run(&sh, "betosync", ["--features=enable-required-features"])? | 
|  | } | 
|  | Subcommand::RunRustFuzzers => run_workspace_fuzz_targets(root_dir)?, | 
|  | Subcommand::License(license_subcommand) => { | 
|  | license_subcommand.run(&LICENSE_CHECKER, root_dir)? | 
|  | } | 
|  | } | 
|  |  | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | fn check_java(sh: &Shell) -> anyhow::Result<()> { | 
|  | let _guard = sh.push_dir("submerge/submerge_java"); | 
|  | cmd!(sh, "./gradlew :lib:test --rerun-tasks").run()?; | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | #[allow(clippy::if_same_then_else)] | 
|  | pub fn verify_ci(root: &path::Path, check_options: &crate::CheckOptions) -> anyhow::Result<()> { | 
|  | if cfg!(target_os = "linux") { | 
|  | run_default_checks(root, check_options)?; | 
|  | } else if cfg!(target_os = "macos") { | 
|  | license::LICENSE_CHECKER.check(root)?; | 
|  | let sh = xshell::Shell::new()?; | 
|  | sh.change_dir(root); | 
|  | check_options.cargo_options.check_workspace( | 
|  | &sh, | 
|  | "betosync", | 
|  | ["--features=enable-required-features"], | 
|  | )?; | 
|  | } else if cfg!(windows) { | 
|  | license::LICENSE_CHECKER.check(root)?; | 
|  | let sh = xshell::Shell::new()?; | 
|  | sh.change_dir(root); | 
|  | check_options.cargo_options.check_workspace( | 
|  | &sh, | 
|  | "betosync", | 
|  | ["--features=enable-required-features"], | 
|  | )?; | 
|  | } else { | 
|  | anyhow::bail!("Unsupported OS for running CI!") | 
|  | } | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | /// Runs checks to ensure lints are passing and all targets are building | 
|  | pub fn run_all_checks(root: &path::Path, check_options: &CheckOptions) -> anyhow::Result<()> { | 
|  | run_default_checks(root, check_options)?; | 
|  | run_workspace_fuzz_targets(root)?; | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | /// Runs default checks that are suitable for verifying a local change. | 
|  | pub fn run_default_checks(root: &path::Path, check_options: &CheckOptions) -> anyhow::Result<()> { | 
|  | license::LICENSE_CHECKER.check(root)?; | 
|  | let sh = xshell::Shell::new()?; | 
|  | sh.change_dir(root); | 
|  | check_options.cargo_options.check_workspace( | 
|  | &sh, | 
|  | "betosync", | 
|  | ["--features=enable-required-features"], | 
|  | )?; | 
|  | check_java(&sh)?; | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | pub fn clean_everything(root: &path::Path) -> anyhow::Result<()> { | 
|  | let sh = Shell::new()?; | 
|  | sh.change_dir(root); | 
|  | cmd!(sh, "cargo clean").run()?; | 
|  | sh.change_dir(root.join("submerge/submerge_java")); | 
|  | cmd!(sh, "./gradlew :tests --rerun-tasks").run()?; | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | #[derive(clap::Parser)] | 
|  | struct Cli { | 
|  | #[clap(subcommand)] | 
|  | subcommand: Subcommand, | 
|  | } | 
|  |  | 
|  | #[derive(clap::Subcommand, Debug, Clone)] | 
|  | enum Subcommand { | 
|  | /// Runs all the checks that CI runs | 
|  | VerifyCi { | 
|  | #[command(flatten)] | 
|  | check_options: CheckOptions, | 
|  | }, | 
|  | /// Runs all available checks, including ones that are not normally run on CI | 
|  | RunAllChecks { | 
|  | #[command(flatten)] | 
|  | check_options: CheckOptions, | 
|  | }, | 
|  | /// Runs the default set of checks suitable for verifying local changes. | 
|  | RunDefaultChecks(CheckOptions), | 
|  | /// Cleans the main workspace and all sub projects - useful if upgrading rust compiler version | 
|  | /// and need dependencies to be compiled with the same version | 
|  | CleanEverything, | 
|  | #[command(flatten)] | 
|  | CargoWorkspace(CargoWorkspaceSubcommand), | 
|  | /// Build and run pure Rust fuzzers for 10000 runs | 
|  | RunRustFuzzers, | 
|  | #[command(flatten)] | 
|  | License(LicenseSubcommand), | 
|  | } | 
|  |  | 
|  | #[derive(clap::Args, Debug, Clone, Default)] | 
|  | pub struct CheckOptions { | 
|  | #[command(flatten)] | 
|  | formatter_options: FormatterOptions, | 
|  | #[command(flatten)] | 
|  | cargo_options: CargoOptions, | 
|  | } |