Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package prek for openSUSE:Factory checked in at 2025-11-27 15:21:08 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/prek (Old) and /work/SRC/openSUSE:Factory/.prek.new.14147 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "prek" Thu Nov 27 15:21:08 2025 rev:4 rq:1320281 version:0.2.19 Changes: -------- --- /work/SRC/openSUSE:Factory/prek/prek.changes 2025-11-24 14:10:19.156119951 +0100 +++ /work/SRC/openSUSE:Factory/.prek.new.14147/prek.changes 2025-11-27 15:22:33.907520108 +0100 @@ -1,0 +2,13 @@ +Thu Nov 27 06:03:24 UTC 2025 - Johannes Kastl <[email protected]> + +- Update to version 0.2.19: + * Performance + - Simplify fix_byte_order_marker hook (#1136) + - Simplify trailing-whitespace hook to improve performance + (#1135) + * Bug fixes + - Close stdin for hook subcommands (#1155) + - Fix parsing Python interpreter info containing non-UTF8 chars + (#1141) + +------------------------------------------------------------------- Old: ---- prek-0.2.18.obscpio New: ---- prek-0.2.19.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ prek.spec ++++++ --- /var/tmp/diff_new_pack.M2M58N/_old 2025-11-27 15:22:37.587675307 +0100 +++ /var/tmp/diff_new_pack.M2M58N/_new 2025-11-27 15:22:37.639677500 +0100 @@ -17,7 +17,7 @@ Name: prek -Version: 0.2.18 +Version: 0.2.19 Release: 0 Summary: Reimagined version of pre-commit, built in Rust License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.M2M58N/_old 2025-11-27 15:22:38.035694201 +0100 +++ /var/tmp/diff_new_pack.M2M58N/_new 2025-11-27 15:22:38.087696395 +0100 @@ -3,7 +3,7 @@ <param name="url">https://github.com/j178/prek.git</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v0.2.18</param> + <param name="revision">v0.2.19</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.M2M58N/_old 2025-11-27 15:22:38.291704998 +0100 +++ /var/tmp/diff_new_pack.M2M58N/_new 2025-11-27 15:22:38.327706516 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/j178/prek.git</param> - <param name="changesrevision">5c9fce63be2dd3740137b7973721377baa80588d</param></service></servicedata> + <param name="changesrevision">bdc40e36aa85f868ed9a8ddbbde1e3d6372cfa75</param></service></servicedata> (No newline at EOF) ++++++ prek-0.2.18.obscpio -> prek-0.2.19.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/CHANGELOG.md new/prek-0.2.19/CHANGELOG.md --- old/prek-0.2.18/CHANGELOG.md 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/CHANGELOG.md 2025-11-26 10:14:35.000000000 +0100 @@ -1,5 +1,25 @@ # Changelog +## 0.2.19 + +Released on 2025-11-26. + +### Performance + +- Simplify `fix_byte_order_marker` hook ([#1136](https://github.com/j178/prek/pull/1136)) +- Simplify `trailing-whitespace` hook to improve performance ([#1135](https://github.com/j178/prek/pull/1135)) + +### Bug fixes + +- Close stdin for hook subcommands ([#1155](https://github.com/j178/prek/pull/1155)) +- Fix parsing Python interpreter info containing non-UTF8 chars ([#1141](https://github.com/j178/prek/pull/1141)) + +### Contributors + +- @chilin0525 +- @nblock +- @j178 + ## 0.2.18 Released on 2025-11-21. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/Cargo.lock new/prek-0.2.19/Cargo.lock --- old/prek-0.2.18/Cargo.lock 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/Cargo.lock 2025-11-26 10:14:35.000000000 +0100 @@ -183,9 +183,9 @@ [[package]] name = "async-compression" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c1f86859c1af3d514fa19e8323147ff10ea98684e6c7b307912509f50e67b2" +checksum = "0e86f6d3dc9dc4352edeea6b8e499e13e3f5dc3b964d7ca5fd411415a3498473" dependencies = [ "compression-codecs", "compression-core", @@ -453,9 +453,9 @@ [[package]] name = "compression-codecs" -version = "0.4.32" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "680dc087785c5230f8e8843e2e57ac7c1c90488b6a91b88caa265410568f441b" +checksum = "302266479cb963552d11bd042013a58ef1adc56768016c8b82b4199488f2d4ad" dependencies = [ "compression-core", "flate2", @@ -465,9 +465,9 @@ [[package]] name = "compression-core" -version = "0.4.30" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9b614a5787ef0c8802a55766480563cb3a93b435898c422ed2a359cf811582" +checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" [[package]] name = "console" @@ -997,12 +997,11 @@ [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -1825,7 +1824,7 @@ [[package]] name = "prek" -version = "0.2.18" +version = "0.2.19" dependencies = [ "anstream", "anstyle-query", @@ -1895,14 +1894,14 @@ [[package]] name = "prek-consts" -version = "0.2.18" +version = "0.2.19" dependencies = [ "tracing", ] [[package]] name = "prek-pty" -version = "0.2.18" +version = "0.2.19" dependencies = [ "rustix", "tokio", @@ -2444,9 +2443,9 @@ [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" dependencies = [ "libc", ] @@ -2562,9 +2561,9 @@ [[package]] name = "syn" -version = "2.0.110" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -2830,9 +2829,9 @@ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456" dependencies = [ "bitflags 2.10.0", "bytes", @@ -3557,18 +3556,18 @@ [[package]] name = "zerocopy" -version = "0.8.28" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43fa6694ed34d6e57407afbccdeecfa268c470a7d2a5b0cf49ce9fcc345afb90" +checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.28" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c640b22cd9817fae95be82f0d2f90b11f7605f6c319d16705c459b27ac2cbc26" +checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5" dependencies = [ "proc-macro2", "quote", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/Cargo.toml new/prek-0.2.19/Cargo.toml --- old/prek-0.2.18/Cargo.toml 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/Cargo.toml 2025-11-26 10:14:35.000000000 +0100 @@ -2,15 +2,15 @@ members = ["crates/*"] [workspace.package] -version = "0.2.18" +version = "0.2.19" edition = "2024" repository = "https://github.com/j178/prek" homepage = "https://prek.j178.dev/" license = "MIT" [workspace.dependencies] -prek-consts = { path = "crates/prek-consts", version = "0.2.18" } -prek-pty = { path = "crates/prek-pty", version = "0.2.18" } +prek-consts = { path = "crates/prek-consts", version = "0.2.19" } +prek-pty = { path = "crates/prek-pty", version = "0.2.19" } rustix = { version = "1.0.8", features = ["pty", "process", "fs", "termios"] } thiserror = { version = "2.0.11" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/README.md new/prek-0.2.19/README.md --- old/prek-0.2.18/README.md 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/README.md 2025-11-26 10:14:35.000000000 +0100 @@ -58,7 +58,7 @@ <!-- linux-standalone-install:start --> ```bash -curl --proto '=https' --tlsv1.2 -LsSf https://github.com/j178/prek/releases/download/v0.2.18/prek-installer.sh | sh +curl --proto '=https' --tlsv1.2 -LsSf https://github.com/j178/prek/releases/download/v0.2.19/prek-installer.sh | sh ``` <!-- linux-standalone-install:end --> @@ -66,7 +66,7 @@ <!-- windows-standalone-install:start --> ```powershell -powershell -ExecutionPolicy ByPass -c "irm https://github.com/j178/prek/releases/download/v0.2.18/prek-installer.ps1 | iex" +powershell -ExecutionPolicy ByPass -c "irm https://github.com/j178/prek/releases/download/v0.2.19/prek-installer.ps1 | iex" ``` <!-- windows-standalone-install:end --> @@ -307,6 +307,7 @@ - [iceberg-python](https://github.com/apache/iceberg-python/pull/2533) - [msgspec](https://github.com/jcrist/msgspec/pull/918) - [humanize](https://github.com/python-humanize/humanize/pull/276) +- [nf-core](https://github.com/nf-core/tools/pull/3899) <!-- why:end --> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/docs/builtin.md new/prek-0.2.19/docs/builtin.md --- old/prek-0.2.18/docs/builtin.md 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/docs/builtin.md 2025-11-26 10:14:35.000000000 +0100 @@ -12,7 +12,7 @@ When you use a standard configuration pointing to a supported repository (like `https://github.com/pre-commit/pre-commit-hooks`), `prek` automatically detects this and runs its internal Rust implementation instead of the Python version defined in the repository. The fast path is activated when the `repo` URL matches `https://github.com/pre-commit/pre-commit-hooks`. No need to change anything in your configuration. -Not that the `rev` field is ignored for detection purposes. +Note that the `rev` field is ignored for detection purposes. This provides a speed boost while keeping your configuration compatible with the original `pre-commit` tool. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/docs/installation.md new/prek-0.2.19/docs/installation.md --- old/prek-0.2.18/docs/installation.md 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/docs/installation.md 2025-11-26 10:14:35.000000000 +0100 @@ -127,7 +127,7 @@ ### Zsh ```bash -COMPLETE=zsh prek completion > "${fpath[1]}/_prek" +COMPLETE=zsh prek > "${fpath[1]}/_prek" ``` ### Fish diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/docs/workspace.md new/prek-0.2.19/docs/workspace.md --- old/prek-0.2.18/docs/workspace.md 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/docs/workspace.md 2025-11-26 10:14:35.000000000 +0100 @@ -89,7 +89,7 @@ 2. `src/` 3. `docs/` 4. `frontend/` -5. `my-monorepo/` (root, last) +5. `./` (root, last) This ensures that more specific configurations (deeper projects) take precedence over general ones. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/mise.toml new/prek-0.2.19/mise.toml --- old/prek-0.2.18/mise.toml 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/mise.toml 2025-11-26 10:14:35.000000000 +0100 @@ -7,14 +7,6 @@ # For snapshot testing cargo-insta = "latest" "cargo:cargo-nextest" = "latest" -# For pre-commit hooks -prek = "latest" - -# Toolchains used in the integration tests. -python = ["3.12"] -node = ["20"] -go = ["1.24"] -ruby = ["3.4"] [tasks.lint] description = "Run formatting and linting" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/pyproject.toml new/prek-0.2.19/pyproject.toml --- old/prek-0.2.18/pyproject.toml 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/pyproject.toml 2025-11-26 10:14:35.000000000 +0100 @@ -1,6 +1,6 @@ [project] name = "prek" -version = "0.2.18" +version = "0.2.19" description = "Better `pre-commit`, re-engineered in Rust" authors = [{ name = "j178", email = "[email protected]" }] requires-python = ">=3.8" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/cli/run/filter.rs new/prek-0.2.19/src/cli/run/filter.rs --- old/prek-0.2.18/src/cli/run/filter.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/cli/run/filter.rs 2025-11-26 10:14:35.000000000 +0100 @@ -4,12 +4,11 @@ use fancy_regex::Regex; use itertools::{Either, Itertools}; use path_clean::PathClean; -use rayon::iter::{IntoParallelRefIterator, ParallelBridge, ParallelIterator}; +use prek_consts::env_vars::EnvVars; +use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use rustc_hash::FxHashSet; use tracing::{debug, error, instrument}; -use prek_consts::env_vars::EnvVars; - use crate::config::Stage; use crate::git::GIT_ROOT; use crate::hook::Hook; @@ -44,10 +43,6 @@ } true } - - pub(crate) fn for_hook(hook: &'a Hook) -> Self { - Self::new(hook.files.as_deref(), hook.exclude.as_deref()) - } } /// Filter files by tags. @@ -102,20 +97,15 @@ ); // TODO: support orphaned project, which does not share files with its parent project. - let mut filenames = filenames - .enumerate() - .par_bridge() - .map(|(i, p)| (i, p.as_path())) - .filter(|(_, filename)| filter.filter(filename)) + let filenames = filenames + .map(PathBuf::as_path) // Collect files that are inside the hook project directory. - .filter(|(_, filename)| filename.starts_with(project.relative_path())) + .filter(|filename| filename.starts_with(project.relative_path())) + .filter(|filename| filter.filter(filename)) .collect::<Vec<_>>(); - // Keep filename order consistent - filenames.sort_by_key(|&(i, _)| i); - Self { - filenames: filenames.into_iter().map(|(_, p)| p).collect(), + filenames, filename_prefix: project.relative_path(), } } @@ -152,7 +142,8 @@ #[instrument(level = "trace", skip_all, fields(hook = ?hook.id))] pub(crate) fn for_hook(&self, hook: &Hook) -> Vec<&Path> { // Filter by hook `files` and `exclude` patterns. - let filter = FilenameFilter::for_hook(hook); + let filter = FilenameFilter::new(hook.files.as_deref(), hook.exclude.as_deref()); + let filenames = self.filenames.par_iter().filter(|filename| { if let Ok(stripped) = filename.strip_prefix(self.filename_prefix) { filter.filter(stripped) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/config.rs new/prek-0.2.19/src/config.rs --- old/prek-0.2.18/src/config.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/config.rs 2025-11-26 10:14:35.000000000 +0100 @@ -674,67 +674,38 @@ for (repo_idx, repo) in config.repos.iter().enumerate() { let repo_prefix = format!("repos[{repo_idx}]"); - match repo { - Repo::Remote(remote) => { - push_unused_paths( - &mut paths, - &repo_prefix, - remote._unused_keys.keys().map(String::as_str), - ); - for (hook_idx, hook) in remote.hooks.iter().enumerate() { - let hook_prefix = format!("{repo_prefix}.hooks[{hook_idx}]"); - push_unused_paths( - &mut paths, - &hook_prefix, - hook.options._unused_keys.keys().map(String::as_str), - ); - } - } - Repo::Local(local) => { - push_unused_paths( - &mut paths, - &repo_prefix, - local._unused_keys.keys().map(String::as_str), - ); - for (hook_idx, hook) in local.hooks.iter().enumerate() { - let hook_prefix = format!("{repo_prefix}.hooks[{hook_idx}]"); - push_unused_paths( - &mut paths, - &hook_prefix, - hook.options._unused_keys.keys().map(String::as_str), - ); - } - } - Repo::Meta(meta) => { - push_unused_paths( - &mut paths, - &repo_prefix, - meta._unused_keys.keys().map(String::as_str), - ); - for (hook_idx, hook) in meta.hooks.iter().enumerate() { - let hook_prefix = format!("{repo_prefix}.hooks[{hook_idx}]"); - push_unused_paths( - &mut paths, - &hook_prefix, - hook.0.options._unused_keys.keys().map(String::as_str), - ); - } - } - Repo::Builtin(builtin) => { - push_unused_paths( - &mut paths, - &repo_prefix, - builtin._unused_keys.keys().map(String::as_str), - ); - for (hook_idx, hook) in builtin.hooks.iter().enumerate() { - let hook_prefix = format!("{repo_prefix}.hooks[{hook_idx}]"); - push_unused_paths( - &mut paths, - &hook_prefix, - hook.0.options._unused_keys.keys().map(String::as_str), - ); - } - } + let (repo_unused_keys, hooks_options): (_, Box<dyn Iterator<Item = &HookOptions>>) = + match repo { + Repo::Remote(remote) => ( + &remote._unused_keys, + Box::new(remote.hooks.iter().map(|h| &h.options)), + ), + Repo::Local(local) => ( + &local._unused_keys, + Box::new(local.hooks.iter().map(|h| &h.options)), + ), + Repo::Meta(meta) => ( + &meta._unused_keys, + Box::new(meta.hooks.iter().map(|h| &h.0.options)), + ), + Repo::Builtin(builtin) => ( + &builtin._unused_keys, + Box::new(builtin.hooks.iter().map(|h| &h.0.options)), + ), + }; + + push_unused_paths( + &mut paths, + &repo_prefix, + repo_unused_keys.keys().map(String::as_str), + ); + for (hook_idx, options) in hooks_options.enumerate() { + let hook_prefix = format!("{repo_prefix}.hooks[{hook_idx}]"); + push_unused_paths( + &mut paths, + &hook_prefix, + options._unused_keys.keys().map(String::as_str), + ); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/git.rs new/prek-0.2.19/src/git.rs --- old/prek-0.2.18/src/git.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/git.rs 2025-11-26 10:14:35.000000000 +0100 @@ -591,6 +591,10 @@ /// Return a list of absolute paths of all git submodules in the repository. #[instrument(level = "trace")] pub(crate) fn list_submodules(git_root: &Path) -> Result<Vec<PathBuf>, Error> { + if !git_root.join(".gitmodules").exists() { + return Ok(vec![]); + } + let git = GIT.as_ref().map_err(|&e| Error::GitNotFound(e))?; let output = std::process::Command::new(git) .current_dir(git_root) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/hooks/pre_commit_hooks/fix_byte_order_marker.rs new/prek-0.2.19/src/hooks/pre_commit_hooks/fix_byte_order_marker.rs --- old/prek-0.2.18/src/hooks/pre_commit_hooks/fix_byte_order_marker.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/hooks/pre_commit_hooks/fix_byte_order_marker.rs 2025-11-26 10:14:35.000000000 +0100 @@ -1,9 +1,8 @@ -use std::io::Write; use std::path::Path; use anyhow::Result; use futures::StreamExt; -use tokio::io::{AsyncReadExt, AsyncSeekExt}; +use tokio::io::AsyncReadExt; use crate::hook::Hook; use crate::run::CONCURRENCY; @@ -34,54 +33,18 @@ async fn fix_file(file_base: &Path, filename: &Path) -> Result<(i32, Vec<u8>)> { let file_path = file_base.join(filename); - // First, just peek at the first 3 bytes to check for BOM let mut file = fs_err::tokio::File::open(&file_path).await?; let mut bom_buffer = [0u8; 3]; - // Read up to 3 bytes (file might be shorter) let bytes_read = file.read(&mut bom_buffer).await?; - // If file is too short or doesn't start with BOM, no changes needed if bytes_read < 3 || bom_buffer != UTF8_BOM { return Ok((0, Vec::new())); } - // File has BOM - now we need to remove it - let metadata = file.metadata().await?; - let file_size = metadata.len(); - - if file_size == 3 { - // File is only BOM, just truncate it - drop(file); - fs_err::tokio::write(&file_path, b"").await?; - } else if file_size <= 64 * 1024 { - // For small files (≤64KB), use the simple approach - drop(file); - let content = fs_err::tokio::read(&file_path).await?; - fs_err::tokio::write(&file_path, &content[3..]).await?; - } else { - // For large files, use streaming to avoid loading everything into memory - // Create a unique temporary filename in the scratch directory - let mut temp_file = tempfile::NamedTempFile::new()?; - - // Reset to position 3 (after BOM) - file.seek(std::io::SeekFrom::Start(3)).await?; - - let mut buffer = vec![0u8; BUFFER_SIZE]; - - loop { - let bytes_read = file.read(&mut buffer).await?; - if bytes_read == 0 { - break; - } - temp_file.write_all(&buffer[..bytes_read])?; - } - - drop(file); - temp_file.flush()?; - - crate::fs::rename_or_copy(&temp_file.into_temp_path(), &file_path).await?; - } + let mut content = Vec::new(); + file.read_to_end(&mut content).await?; + fs_err::tokio::write(&file_path, &content).await?; Ok(( 1, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/hooks/pre_commit_hooks/fix_trailing_whitespace.rs new/prek-0.2.19/src/hooks/pre_commit_hooks/fix_trailing_whitespace.rs --- old/prek-0.2.18/src/hooks/pre_commit_hooks/fix_trailing_whitespace.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/hooks/pre_commit_hooks/fix_trailing_whitespace.rs 2025-11-26 10:14:35.000000000 +0100 @@ -6,14 +6,11 @@ use bstr::ByteSlice; use clap::Parser; use futures::StreamExt; -use tempfile::NamedTempFile; -use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader, BufWriter}; use crate::hook::Hook; use crate::run::CONCURRENCY; const MARKDOWN_LINE_BREAK: &[u8] = b" "; -const BUFFER_SIZE_THRESHOLD: usize = 64 * 1024; // 64KB #[derive(Clone)] struct Chars(Vec<char>); @@ -128,16 +125,12 @@ }; let file_path = file_base.join(filename); - let file = fs_err::tokio::File::open(&file_path).await?; - let file_len = file.metadata().await?.len(); + let content = fs_err::tokio::read(&file_path).await?; - let mut buf_writer = create_buffer(usize::try_from(file_len)?)?; - let mut buf_reader = BufReader::new(file); - - let mut line = Vec::new(); + let mut output = Vec::with_capacity(content.len()); let mut modified = false; - while buf_reader.read_until(b'\n', &mut line).await? != 0 { - let line_ending = detect_line_ending(&line); + for line in content.split_inclusive(|&b| b == b'\n') { + let line_ending = detect_line_ending(line); let mut trimmed = &line[..line.len() - line_ending.len()]; let markdown_end = needs_markdown_break(is_markdown, trimmed); @@ -151,115 +144,24 @@ trimmed = trimmed.trim_end_with(|c| chars.contains(&c)); } - buf_writer.write(trimmed).await?; + output.extend_from_slice(trimmed); if markdown_end { - buf_writer.write(MARKDOWN_LINE_BREAK).await?; + output.extend_from_slice(MARKDOWN_LINE_BREAK); modified |= trimmed.len() + MARKDOWN_LINE_BREAK.len() + line_ending.len() != line.len(); } else { modified |= trimmed.len() + line_ending.len() != line.len(); } - buf_writer.write(line_ending).await?; - line.clear(); + output.extend_from_slice(line_ending); } - drop(buf_reader); if modified { - buf_writer.flush_to_file(&file_path).await?; + fs_err::tokio::write(&file_path, &output).await?; Ok((1, format!("Fixing {}\n", filename.display()).into_bytes())) } else { - drop(buf_writer); Ok((0, Vec::new())) } } -trait AsyncWriteBuffer { - async fn write(&mut self, data: &[u8]) -> Result<()>; - async fn flush_to_file(&mut self, filename: &Path) -> Result<()>; -} - -struct MemoryBuffer(Vec<u8>); - -impl MemoryBuffer { - pub fn new(mut file_len: usize) -> Self { - if file_len > BUFFER_SIZE_THRESHOLD { - file_len = BUFFER_SIZE_THRESHOLD; - } - Self(Vec::with_capacity(file_len)) - } -} - -impl AsyncWriteBuffer for MemoryBuffer { - async fn write(&mut self, data: &[u8]) -> Result<()> { - self.0.extend_from_slice(data); - Ok(()) - } - - async fn flush_to_file(&mut self, filename: &Path) -> Result<()> { - fs_err::tokio::write(filename, &self.0).await?; - Ok(()) - } -} - -struct TempFileBuffer { - buf_writer: BufWriter<tokio::fs::File>, - named_temp_file: NamedTempFile, -} - -impl TempFileBuffer { - pub fn new() -> Result<Self> { - let named_temp_file = NamedTempFile::new()?; - let temp_file = tokio::fs::File::from_std(named_temp_file.reopen()?); - let buf_writer = BufWriter::new(temp_file); - - Ok(Self { - buf_writer, - named_temp_file, - }) - } -} - -impl AsyncWriteBuffer for TempFileBuffer { - async fn write(&mut self, data: &[u8]) -> Result<()> { - self.buf_writer.write_all(data).await?; - Ok(()) - } - - async fn flush_to_file(&mut self, filename: &Path) -> Result<()> { - self.buf_writer.flush().await?; - crate::fs::rename_or_copy(self.named_temp_file.path(), Path::new(filename)).await?; - Ok(()) - } -} - -enum Buffer { - Memory(MemoryBuffer), - Temp(TempFileBuffer), -} - -impl AsyncWriteBuffer for Buffer { - async fn write(&mut self, data: &[u8]) -> Result<()> { - match self { - Buffer::Memory(b) => b.write(data).await, - Buffer::Temp(b) => b.write(data).await, - } - } - - async fn flush_to_file(&mut self, filename: &Path) -> Result<()> { - match self { - Buffer::Memory(b) => b.flush_to_file(filename).await, - Buffer::Temp(b) => b.flush_to_file(filename).await, - } - } -} - -fn create_buffer(file_len: usize) -> Result<Buffer> { - if file_len <= BUFFER_SIZE_THRESHOLD { - Ok(Buffer::Memory(MemoryBuffer::new(file_len))) - } else { - Ok(Buffer::Temp(TempFileBuffer::new()?)) - } -} - fn detect_line_ending(line: &[u8]) -> &[u8] { if line.ends_with(b"\r\n") { b"\r\n" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/languages/docker.rs new/prek-0.2.19/src/languages/docker.rs --- old/prek-0.2.18/src/languages/docker.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/languages/docker.rs 2025-11-26 10:14:35.000000000 +0100 @@ -4,7 +4,7 @@ use std::fs; use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; -use std::process::Command; +use std::process::{Command, Stdio}; use std::str::FromStr; use std::sync::{Arc, LazyLock}; @@ -462,6 +462,7 @@ .args(&hook.args) .args(batch) .check(false) + .stdin(Stdio::null()) .output() .await?; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/languages/docker_image.rs new/prek-0.2.19/src/languages/docker_image.rs --- old/prek-0.2.18/src/languages/docker_image.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/languages/docker_image.rs 2025-11-26 10:14:35.000000000 +0100 @@ -1,4 +1,5 @@ use std::path::Path; +use std::process::Stdio; use std::sync::Arc; use anyhow::Result; @@ -42,6 +43,7 @@ .args(&hook.args) .args(batch) .check(false) + .stdin(Stdio::null()) .output() .await?; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/languages/golang/golang.rs new/prek-0.2.19/src/languages/golang/golang.rs --- old/prek-0.2.18/src/languages/golang/golang.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/languages/golang/golang.rs 2025-11-26 10:14:35.000000000 +0100 @@ -1,5 +1,6 @@ use std::ops::Deref; use std::path::{Path, PathBuf}; +use std::process::Stdio; use std::sync::Arc; use anyhow::Context; @@ -143,13 +144,14 @@ let mut output = Cmd::new(&entry[0], "go hook") .current_dir(hook.work_dir()) .args(&entry[1..]) - .env("PATH", &new_path) + .env(EnvVars::PATH, &new_path) .env(EnvVars::GOTOOLCHAIN, "local") .env(EnvVars::GOBIN, &go_bin) .envs(go_envs.iter().copied()) .args(&hook.args) .args(batch) .check(false) + .stdin(Stdio::null()) .pty_output() .await?; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/languages/lua.rs new/prek-0.2.19/src/languages/lua.rs --- old/prek-0.2.18/src/languages/lua.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/languages/lua.rs 2025-11-26 10:14:35.000000000 +0100 @@ -1,4 +1,5 @@ use std::path::{Path, PathBuf}; +use std::process::Stdio; use std::sync::Arc; use anyhow::{Context, Result}; @@ -144,12 +145,13 @@ let mut output = Cmd::new(&entry[0], "run lua command") .current_dir(hook.work_dir()) .args(&entry[1..]) - .env("PATH", &new_path) + .env(EnvVars::PATH, &new_path) .env(EnvVars::LUA_PATH, &lua_path) .env(EnvVars::LUA_CPATH, &lua_cpath) .args(&hook.args) .args(batch) .check(false) + .stdin(Stdio::null()) .pty_output() .await?; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/languages/mod.rs new/prek-0.2.19/src/languages/mod.rs --- old/prek-0.2.18/src/languages/mod.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/languages/mod.rs 2025-11-26 10:14:35.000000000 +0100 @@ -16,7 +16,6 @@ use crate::hook::{Hook, InstallInfo, InstalledHook, Repo}; use crate::identify::parse_shebang; use crate::store::Store; -use crate::version::version; use crate::{archive, hooks, warn_user_once}; mod docker; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/languages/node/node.rs new/prek-0.2.19/src/languages/node/node.rs --- old/prek-0.2.18/src/languages/node/node.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/languages/node/node.rs 2025-11-26 10:14:35.000000000 +0100 @@ -1,6 +1,7 @@ use std::borrow::Cow; use std::env::consts::EXE_EXTENSION; use std::path::{Path, PathBuf}; +use std::process::Stdio; use std::sync::Arc; use anyhow::{Context, Result}; @@ -112,7 +113,7 @@ .arg("--no-audit") .arg("--install-links") .args(&*deps) - .env("PATH", new_path) + .env(EnvVars::PATH, new_path) .env(EnvVars::NPM_CONFIG_PREFIX, &info.env_path) .env_remove(EnvVars::NPM_CONFIG_USERCONFIG) .env(EnvVars::NODE_PATH, &lib_dir) @@ -162,13 +163,14 @@ let mut output = Cmd::new(&entry[0], "node hook") .current_dir(hook.work_dir()) .args(&entry[1..]) - .env("PATH", &new_path) + .env(EnvVars::PATH, &new_path) .env(EnvVars::NPM_CONFIG_PREFIX, env_dir) .env_remove(EnvVars::NPM_CONFIG_USERCONFIG) .env(EnvVars::NODE_PATH, lib_dir(env_dir)) .args(&hook.args) .args(batch) .check(false) + .stdin(Stdio::null()) .pty_output() .await?; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/languages/python/python.rs new/prek-0.2.19/src/languages/python/python.rs --- old/prek-0.2.18/src/languages/python/python.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/languages/python/python.rs 2025-11-26 10:14:35.000000000 +0100 @@ -1,11 +1,12 @@ use std::env::consts::EXE_EXTENSION; use std::path::{Path, PathBuf}; +use std::process::Stdio; use std::sync::Arc; use anyhow::{Context, Result}; -use tracing::{debug, trace}; - use prek_consts::env_vars::EnvVars; +use serde::Deserialize; +use tracing::{debug, trace}; use crate::cli::reporter::HookInstallReporter; use crate::hook::InstalledHook; @@ -28,10 +29,19 @@ } pub(crate) async fn query_python_info(python: &Path) -> Result<PythonInfo> { + #[derive(Deserialize)] + struct QueryPythonInfo { + version: semver::Version, + base_exec_prefix: PathBuf, + } + static QUERY_PYTHON_INFO: &str = indoc::indoc! {r#" - import sys - print(f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}") - print(sys.base_exec_prefix) + import sys, json + info = { + "version": ".".join(map(str, sys.version_info[:3])), + "base_exec_prefix": sys.base_exec_prefix, + } + print(json.dumps(info)) "#}; let stdout = Cmd::new(python, "python -c") @@ -43,22 +53,12 @@ .await? .stdout; - let stdout = String::from_utf8(stdout).context("Failed to parse Python info output")?; - let mut lines = stdout.lines(); - let version = lines - .next() - .context("Failed to get Python version")? - .to_string() - .parse() - .context("Failed to parse Python version")?; - let base_exec_prefix = lines - .next() - .context("Failed to get Python base_exec_prefix")? - .to_string(); - let python_exec = python_exec(Path::new(&base_exec_prefix)); + let info: QueryPythonInfo = + serde_json::from_slice(&stdout).context("Failed to parse Python info JSON")?; + let python_exec = python_exec(&info.base_exec_prefix); Ok(PythonInfo { - version, + version: info.version, python_exec, }) } @@ -192,6 +192,7 @@ .args(&hook.args) .args(batch) .check(false) + .stdin(Stdio::null()) .pty_output() .await?; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/languages/python/version.rs new/prek-0.2.19/src/languages/python/version.rs --- old/prek-0.2.18/src/languages/python/version.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/languages/python/version.rs 2025-11-26 10:14:35.000000000 +0100 @@ -4,7 +4,6 @@ use std::str::FromStr; use crate::hook::InstallInfo; -use crate::languages::version; use crate::languages::version::{Error, try_into_u64_slice}; #[derive(Debug, Clone, PartialEq, Eq)] @@ -33,7 +32,7 @@ /// - `/path/to/python3.12` // TODO: support version like `3.8b1`, `3.8rc2`, `python3.8t`, `python3.8-64`, `pypy3.8`. impl FromStr for PythonRequest { - type Err = version::Error; + type Err = Error; fn from_str(request: &str) -> Result<Self, Self::Err> { if request.is_empty() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/languages/ruby/installer.rs new/prek-0.2.19/src/languages/ruby/installer.rs --- old/prek-0.2.18/src/languages/ruby/installer.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/languages/ruby/installer.rs 2025-11-26 10:14:35.000000000 +0100 @@ -361,11 +361,8 @@ .output() .await?; - let output_str = String::from_utf8(output.stdout)?; - let mut lines = output_str.lines(); - + let mut lines = str::from_utf8(&output.stdout)?.lines(); let engine = lines.next().unwrap_or("ruby").to_string(); - let version_str = lines.next().context("No version in Ruby output")?.trim(); let version = semver::Version::parse(version_str) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/languages/ruby/ruby.rs new/prek-0.2.19/src/languages/ruby/ruby.rs --- old/prek-0.2.18/src/languages/ruby/ruby.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/languages/ruby/ruby.rs 2025-11-26 10:14:35.000000000 +0100 @@ -1,4 +1,5 @@ use std::path::{Path, PathBuf}; +use std::process::Stdio; use std::sync::Arc; use anyhow::{Context, Result}; @@ -109,8 +110,8 @@ .output() .await?; - let version_str = String::from_utf8(output.stdout)?.trim().to_string(); - let actual_version = semver::Version::parse(&version_str) + let version_str = str::from_utf8(&output.stdout)?.trim(); + let actual_version = semver::Version::parse(version_str) .with_context(|| format!("Failed to parse Ruby version: {version_str}"))?; if actual_version != info.language_version { @@ -171,6 +172,7 @@ .args(&hook.args) .args(batch) .check(false) + .stdin(Stdio::null()) .pty_output() .await?; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/languages/script.rs new/prek-0.2.19/src/languages/script.rs --- old/prek-0.2.18/src/languages/script.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/languages/script.rs 2025-11-26 10:14:35.000000000 +0100 @@ -1,4 +1,5 @@ use std::path::Path; +use std::process::Stdio; use std::sync::Arc; use anyhow::Result; @@ -52,6 +53,7 @@ .args(&hook.args) .args(batch) .check(false) + .stdin(Stdio::null()) .pty_output() .await?; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/languages/system.rs new/prek-0.2.19/src/languages/system.rs --- old/prek-0.2.18/src/languages/system.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/languages/system.rs 2025-11-26 10:14:35.000000000 +0100 @@ -1,4 +1,5 @@ use std::path::Path; +use std::process::Stdio; use std::sync::Arc; use anyhow::Result; @@ -42,6 +43,7 @@ .args(&hook.args) .args(batch) .check(false) + .stdin(Stdio::null()) .pty_output() .await?; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/process.rs new/prek-0.2.19/src/process.rs --- old/prek-0.2.18/src/process.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/process.rs 2025-11-26 10:14:35.000000000 +0100 @@ -195,9 +195,9 @@ } let (mut pty, pts) = prek_pty::open()?; - let (stdin, stdout, stderr) = pts.setup_subprocess()?; + let (_, stdout, stderr) = pts.setup_subprocess()?; - self.inner.stdin(stdin); + self.inner.stdin(Stdio::null()); self.inner.stdout(stdout); self.inner.stderr(stderr); @@ -482,7 +482,7 @@ } write!(f, " {}", arg.to_string_lossy())?; len += arg.len() + 1; - if len > 100 { + if len > 120 { write!(f, " [...]",)?; break; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/run.rs new/prek-0.2.19/src/run.rs --- old/prek-0.2.18/src/run.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/run.rs 2025-11-26 10:14:35.000000000 +0100 @@ -117,11 +117,11 @@ let max_per_batch = max(4, filenames.len().div_ceil(concurrency)); let mut max_cli_length = platform_max_cli_length(); - let entry_lower = &entry[0].to_ascii_lowercase(); + let cmd = Path::new(&entry[0]); if cfg!(windows) - && [".bat", ".cmd"] - .iter() - .any(|ext| entry_lower.ends_with(ext)) + && cmd.extension().is_some_and(|ext| { + ext.eq_ignore_ascii_case("cmd") || ext.eq_ignore_ascii_case("bat") + }) { // Reduce max length for batch files on Windows due to cmd.exe limitations. // 1024 is additionally subtracted to give headroom for further diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/src/workspace.rs new/prek-0.2.19/src/workspace.rs --- old/prek-0.2.18/src/workspace.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/src/workspace.rs 2025-11-26 10:14:35.000000000 +0100 @@ -22,7 +22,6 @@ use crate::git::GIT_ROOT; use crate::hook::{self, Hook, HookBuilder, Repo}; use crate::store::{CacheBucket, Store}; -use crate::workspace::Error::MissingPreCommitConfig; use crate::{git, store, warn_user}; #[derive(Error, Debug)] @@ -554,7 +553,7 @@ .ancestors() .take_while(|p| git_root.parent().map(|root| *p != root).unwrap_or(true)) .find(|p| p.join(CONFIG_FILE).is_file() || p.join(ALT_CONFIG_FILE).is_file()) - .ok_or(MissingPreCommitConfig)? + .ok_or(Error::MissingPreCommitConfig)? .to_path_buf(); debug!("Found workspace root at `{}`", workspace_root.display()); @@ -634,7 +633,7 @@ projects.retain(|p| selectors.matches_path(p.relative_path())); } if projects.is_empty() { - return Err(MissingPreCommitConfig); + return Err(Error::MissingPreCommitConfig); } let mut workspace = Self { root, projects }; @@ -651,7 +650,10 @@ let projects = Mutex::new(Ok(Vec::new())); let git_root = GIT_ROOT.as_ref().map_err(|e| Error::Git(e.into()))?; - let submodules = git::list_submodules(git_root).unwrap_or_default(); + let submodules = git::list_submodules(git_root).unwrap_or_else(|e| { + error!("Failed to list git submodules: {e}"); + Vec::new() + }); ignore::WalkBuilder::new(root) .follow_links(false) @@ -721,7 +723,7 @@ let projects = projects.into_inner().unwrap()?; if projects.is_empty() { - return Err(MissingPreCommitConfig); + return Err(Error::MissingPreCommitConfig); } Ok(projects) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/prek-0.2.18/tests/run.rs new/prek-0.2.19/tests/run.rs --- old/prek-0.2.18/tests/run.rs 2025-11-21 13:41:20.000000000 +0100 +++ new/prek-0.2.19/tests/run.rs 2025-11-26 10:14:35.000000000 +0100 @@ -2500,3 +2500,48 @@ caused by: Failed to parse entry: entry is empty "); } + +/// Test that hooks are run with stdin closed. +#[test] +fn run_with_stdin_closed() { + let context = TestContext::new(); + context.init_project(); + context.write_pre_commit_config(indoc::indoc! {r#" + repos: + - repo: local + hooks: + - id: check-stdin + name: check-stdin + language: python + entry: python -c 'import sys; sys.stdin.read(); print("STDIN closed")' + pass_filenames: false + verbose: true + "#}); + context.git_add("."); + + cmd_snapshot!(context.filters(), context.run(), @r" + success: true + exit_code: 0 + ----- stdout ----- + check-stdin..............................................................Passed + - hook id: check-stdin + - duration: [TIME] + + STDIN closed + + ----- stderr ----- + "); + + cmd_snapshot!(context.filters(), context.run().arg("--color").arg("always"), @r" + success: true + exit_code: 0 + ----- stdout ----- + check-stdin..............................................................[42mPassed[49m + [2m- hook id: check-stdin[0m + [2m- duration: [TIME][0m + + STDIN closed + + ----- stderr ----- + "); +} ++++++ prek.obsinfo ++++++ --- /var/tmp/diff_new_pack.M2M58N/_old 2025-11-27 15:22:39.719765222 +0100 +++ /var/tmp/diff_new_pack.M2M58N/_new 2025-11-27 15:22:39.787768089 +0100 @@ -1,5 +1,5 @@ name: prek -version: 0.2.18 -mtime: 1763728880 -commit: 5c9fce63be2dd3740137b7973721377baa80588d +version: 0.2.19 +mtime: 1764148475 +commit: bdc40e36aa85f868ed9a8ddbbde1e3d6372cfa75 ++++++ vendor.tar.zst ++++++ /work/SRC/openSUSE:Factory/prek/vendor.tar.zst /work/SRC/openSUSE:Factory/.prek.new.14147/vendor.tar.zst differ: char 7, line 1
