Browse Source

ci: Install pre-commit crate dependencies with cargo-binstall

It should be quicker than compiling them with `cargo install`
merge-requests/2136/head
Kévin Commaille 2 months ago
parent
commit
bd7d53c646
No known key found for this signature in database
GPG Key ID: F26F4BE20A08255B
  1. 2
      .gitlab-ci/check.yml
  2. 23
      hooks/checks/src/main.rs
  3. 69
      hooks/checks/src/utils.rs

2
.gitlab-ci/check.yml

@ -8,7 +8,7 @@ pre-commit-checks:
image: "rustlang/rust:nightly-slim"
interruptible: true
script:
- RUST_BACKTRACE=1 cargo run --manifest-path hooks/checks/Cargo.toml -- --verbose --force-install
- RUST_BACKTRACE=1 cargo run --manifest-path hooks/checks/Cargo.toml -- --verbose --force-install --cargo-binstall
# Checks needing dependencies in the Flatpak runtime
flatpak-checks:

23
hooks/checks/src/main.rs

@ -10,8 +10,8 @@ use std::{
mod utils;
use crate::utils::{
CargoManifest, CheckDependency, CommandData, GitStagedFiles, InstallationCommand,
check_files_sorted, file_contains, load_files, print_error, visit_dir,
CargoInstallMethod, CargoManifest, CheckDependency, CommandData, GitStagedFiles,
InstallationCommand, check_files_sorted, file_contains, load_files, print_error, visit_dir,
};
/// The path to the directory containing the workspace.
@ -71,6 +71,9 @@ impl ScriptCommand {
"force-install" => {
check_cmd.force_install = true;
}
"cargo-binstall" => {
check_cmd.cargo_install_method = CargoInstallMethod::CargoBinstall;
}
"verbose" => {
VERBOSE.store(true, Ordering::Relaxed);
}
@ -153,6 +156,8 @@ USAGE: {name} [OPTIONS]
OPTIONS:
-s, --git-staged Only check files staged to be committed
-f, --force-install Install missing dependencies without asking
--cargo-binstall Use cargo-binstall instead of `cargo install` when installing
missing crate dependencies
-v, --verbose Use verbose output
--version Print the version of this script
-h, --help Print this help and exit
@ -185,6 +190,8 @@ struct CheckCmd {
staged_files: Option<GitStagedFiles>,
/// Whether to install missing dependencies without asking.
force_install: bool,
/// Which program to use to install crate dependencies.
cargo_install_method: CargoInstallMethod,
}
impl CheckCmd {
@ -216,7 +223,7 @@ impl CheckCmd {
&["component", "add", "--toolchain", "nightly", "rustfmt"],
)),
}
.check(self.force_install)?;
.check(self.force_install, self.cargo_install_method)?;
if let Some(staged_files) = &self.staged_files {
let cmd = CommandData::new(
@ -267,7 +274,7 @@ impl CheckCmd {
&["component", "add", "clippy"],
)),
}
.check(self.force_install)?;
.check(self.force_install, self.cargo_install_method)?;
let manifest_path = format!("{WORKSPACE_DIR}/hooks/checks/Cargo.toml");
@ -295,7 +302,7 @@ impl CheckCmd {
version: CommandData::new("typos", &["--version"]),
install: InstallationCommand::Cargo("typos-cli"),
}
.check(self.force_install)?;
.check(self.force_install, self.cargo_install_method)?;
let cmd = CommandData::new("typos", &["--color", "always"]).print_output();
@ -322,7 +329,7 @@ impl CheckCmd {
version: CommandData::new("cargo-machete", &["--version"]),
install: InstallationCommand::Cargo("cargo-machete"),
}
.check(self.force_install)?;
.check(self.force_install, self.cargo_install_method)?;
let output = CommandData::new("cargo-machete", &["--with-metadata"])
.print_output()
@ -345,7 +352,7 @@ impl CheckCmd {
version: CommandData::new("cargo", &["deny", "--version"]),
install: InstallationCommand::Cargo("cargo-deny"),
}
.check(self.force_install)?;
.check(self.force_install, self.cargo_install_method)?;
let output = CommandData::new("cargo", &["deny", "check"])
.print_output()
@ -625,7 +632,7 @@ impl CheckCmd {
version: CommandData::new("cargo", &["sort", "--version"]),
install: InstallationCommand::Cargo("cargo-sort"),
}
.check(self.force_install)?;
.check(self.force_install, self.cargo_install_method)?;
let output = CommandData::new(
"cargo",

69
hooks/checks/src/utils.rs

@ -116,7 +116,11 @@ impl CheckDependency {
/// Check whether the dependency is available.
///
/// Returns `Ok` if the dependency was available or successfully installed.
pub(crate) fn check(self, force_install: bool) -> Result<(), ScriptError> {
pub(crate) fn check(
self,
force_install: bool,
cargo_method: CargoInstallMethod,
) -> Result<(), ScriptError> {
let Self {
name,
version,
@ -136,12 +140,14 @@ impl CheckDependency {
}
if !force_install {
self.ask_install()?;
self.ask_install(cargo_method)?;
}
println!("\x1B[1;92mInstalling\x1B[0m {name}…");
if install.run()?.status.success() && version.run()?.status.success() {
if install.run(force_install, cargo_method)?.status.success()
&& version.run()?.status.success()
{
// The dependency was installed successfully.
Ok(())
} else {
@ -152,7 +158,7 @@ impl CheckDependency {
/// Ask the user whether we should try to install the dependency, if we are
/// in a terminal.
fn ask_install(self) -> Result<(), ScriptError> {
fn ask_install(self, cargo_method: CargoInstallMethod) -> Result<(), ScriptError> {
let name = self.name;
let stdin = stdin();
@ -163,7 +169,7 @@ impl CheckDependency {
}
println!("{name} is needed for this check, but it isn’t available\n");
println!("y: Install {name} via {}", self.install.via());
println!("y: Install {name} via {}", self.install.via(cargo_method));
println!("N: Don’t install {name} and abort checks\n");
let mut input = String::new();
@ -313,24 +319,65 @@ pub(crate) enum InstallationCommand {
impl InstallationCommand {
/// The program used for the installation.
pub(crate) fn via(self) -> &'static str {
pub(crate) fn via(self, cargo_method: CargoInstallMethod) -> &'static str {
match self {
Self::Cargo(_) => "cargo",
Self::Cargo(_) => cargo_method.name(),
Self::Custom(cmd) => cmd.program,
}
}
/// Run this command.
pub(crate) fn run(self) -> Result<Output, ScriptError> {
pub(crate) fn run(
self,
force_install: bool,
cargo_method: CargoInstallMethod,
) -> Result<Output, ScriptError> {
match self {
Self::Cargo(dep) => CommandData::new("cargo", &["install"])
.print_output()
.run_with_args(&[dep]),
Self::Cargo(dep) => cargo_method.run(dep, force_install),
Self::Custom(cmd) => cmd.print_output().run(),
}
}
}
/// The method used to install crate dependencies.
#[derive(Clone, Copy, Default)]
pub(crate) enum CargoInstallMethod {
/// Use `cargo install`.
#[default]
Cargo,
/// Use `cargo-binstall`.
CargoBinstall,
}
impl CargoInstallMethod {
/// The name of this method.
fn name(self) -> &'static str {
match self {
Self::Cargo => "cargo",
Self::CargoBinstall => "cargo-binstall",
}
}
/// Run tis method for the given dependency.
fn run(self, dep: &str, force_install: bool) -> Result<Output, ScriptError> {
if matches!(self, Self::CargoBinstall) {
CheckDependency {
name: "cargo-binstall",
version: CommandData::new("cargo", &["binstall", "-V"]),
install: InstallationCommand::Cargo("cargo-binstall"),
}
.check(force_install, CargoInstallMethod::Cargo)?;
}
let cmd = match self {
Self::Cargo => CommandData::new("cargo", &["install"]),
Self::CargoBinstall => CommandData::new("cargo", &["binstall"]),
};
cmd.print_output().run_with_args(&[dep])
}
}
/// Visit the given directory recursively and apply the given function to files.
pub(crate) fn visit_dir(dir: &Path, on_file: &mut dyn FnMut(PathBuf)) {
let dir_entries = match fs::read_dir(dir) {

Loading…
Cancel
Save