diff --git a/Cargo.lock b/Cargo.lock index 9708413..3b47593 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1644,6 +1644,15 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook-registry" +version = "1.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" +dependencies = [ + "libc", +] + [[package]] name = "similar" version = "2.7.0" @@ -1782,6 +1791,7 @@ dependencies = [ "mio", "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", "tokio-macros", "windows-sys 0.61.1", diff --git a/cpp-linter/Cargo.toml b/cpp-linter/Cargo.toml index 96c035c..487c102 100644 --- a/cpp-linter/Cargo.toml +++ b/cpp-linter/Cargo.toml @@ -28,7 +28,7 @@ reqwest = "0.12.24" semver = "1.0.27" serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.145" -tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread"] } +tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread", "process"] } tokio-macros = "2.5.0" tokio-stream = "0.1.17" which = "8.0.0" diff --git a/cpp-linter/src/clang_tools/clang_format.rs b/cpp-linter/src/clang_tools/clang_format.rs index b89d509..a4ac029 100644 --- a/cpp-linter/src/clang_tools/clang_format.rs +++ b/cpp-linter/src/clang_tools/clang_format.rs @@ -3,13 +3,13 @@ use std::{ fs, - process::Command, - sync::{Arc, Mutex, MutexGuard}, + sync::{Arc, Mutex}, }; -use anyhow::{Context, Result}; +use anyhow::{Context, Result, anyhow}; use log::Level; use serde::Deserialize; +use tokio::process::Command; // project-specific crates/modules use super::MakeSuggestions; @@ -81,58 +81,61 @@ pub fn tally_format_advice(files: &[Arc>]) -> u64 { } /// Run clang-tidy for a specific `file`, then parse and return it's XML output. -pub fn run_clang_format( - file: &mut MutexGuard, +pub async fn run_clang_format( + file: &Arc>, clang_params: &ClangParams, ) -> Result> { - let mut cmd = Command::new(clang_params.clang_format_command.as_ref().unwrap()); let mut logs = vec![]; - cmd.args(["--style", &clang_params.style]); - let ranges = file.get_ranges(&clang_params.lines_changed_only); - for range in &ranges { - cmd.arg(format!("--lines={}:{}", range.start(), range.end())); - } - let file_name = file.name.to_string_lossy().to_string(); - cmd.arg(file.name.to_path_buf().as_os_str()); + let program = clang_params.clang_format_command.as_ref().unwrap(); + let (file_name, mut args, ranges) = { + let mut args = vec![]; + let file = file + .lock() + .map_err(|e| anyhow!("Failed to lock mutex: {e:?}"))?; + args.extend(["--style".to_string(), clang_params.style.clone()]); + let ranges = file.get_ranges(&clang_params.lines_changed_only); + for range in &ranges { + args.push(format!("--lines={}:{}", range.start(), range.end())); + } + let file_name = file.name.to_string_lossy().to_string(); + (file_name, args, ranges) + }; + let mut cmd = Command::new(program); + cmd.args(&args); let patched = if !clang_params.format_review { None } else { logs.push(( Level::Info, format!( - "Getting format fixes with \"{} {}\"", - clang_params - .clang_format_command - .as_ref() - .unwrap() - .to_str() - .unwrap_or_default(), - cmd.get_args() - .map(|a| a.to_string_lossy()) - .collect::>() - .join(" ") + "Getting format fixes with \"{} {} {}\"", + program.to_string_lossy(), + args.join(" "), + &file_name ), )); + cmd.arg(&file_name); Some( cmd.output() + .await .with_context(|| format!("Failed to get fixes from clang-format: {file_name}"))? .stdout, ) }; - cmd.arg("--output-replacements-xml"); + args.extend(["--output-replacements-xml".to_string(), file_name.clone()]); + let mut cmd = Command::new(program); + cmd.args(&args); logs.push(( log::Level::Info, format!( "Running \"{} {}\"", - cmd.get_program().to_string_lossy(), - cmd.get_args() - .map(|x| x.to_string_lossy()) - .collect::>() - .join(" ") + program.to_string_lossy(), + args.join(" ") ), )); let output = cmd .output() + .await .with_context(|| format!("Failed to get replacements from clang-format: {file_name}"))?; if !output.stderr.is_empty() || !output.status.success() { logs.push(( @@ -155,7 +158,7 @@ pub fn run_clang_format( }; format_advice.patched = patched; if !format_advice.replacements.is_empty() { - let original_contents = fs::read(&file.name).with_context(|| { + let original_contents = fs::read(&file_name).with_context(|| { format!( "Failed to read file's original content before translating byte offsets: {file_name}", ) @@ -178,7 +181,12 @@ pub fn run_clang_format( } format_advice.replacements = filtered_replacements; } - file.format_advice = Some(format_advice); + { + let mut file = file + .lock() + .map_err(|e| anyhow!("Failed to lock mutex: {e:?}"))?; + file.format_advice = Some(format_advice); + } Ok(logs) } diff --git a/cpp-linter/src/clang_tools/clang_tidy.rs b/cpp-linter/src/clang_tools/clang_tidy.rs index d8610ae..1288b65 100644 --- a/cpp-linter/src/clang_tools/clang_tidy.rs +++ b/cpp-linter/src/clang_tools/clang_tidy.rs @@ -5,14 +5,14 @@ use std::{ env::{consts::OS, current_dir}, fs, path::PathBuf, - process::Command, - sync::{Arc, Mutex, MutexGuard}, + sync::{Arc, Mutex}, }; // non-std crates -use anyhow::{Context, Result}; +use anyhow::{Context, Result, anyhow}; use regex::Regex; use serde::Deserialize; +use tokio::process::Command; // project-specific modules/crates use super::MakeSuggestions; @@ -247,39 +247,45 @@ pub fn tally_tidy_advice(files: &[Arc>]) -> u64 { } /// Run clang-tidy, then parse and return it's output. -pub fn run_clang_tidy( - file: &mut MutexGuard, +pub async fn run_clang_tidy( + file: &Arc>, clang_params: &ClangParams, ) -> Result> { - let mut cmd = Command::new(clang_params.clang_tidy_command.as_ref().unwrap()); let mut logs = vec![]; - if !clang_params.tidy_checks.is_empty() { - cmd.args(["-checks", &clang_params.tidy_checks]); - } - if let Some(db) = &clang_params.database { - cmd.args(["-p", &db.to_string_lossy()]); - } - for arg in &clang_params.extra_args { - cmd.args(["--extra-arg", format!("\"{}\"", arg).as_str()]); - } - let file_name = file.name.to_string_lossy().to_string(); - let ranges = file.get_ranges(&clang_params.lines_changed_only); - if !ranges.is_empty() { - let filter = format!( - "[{{\"name\":{:?},\"lines\":{:?}}}]", - &file_name.replace('/', if OS == "windows" { "\\" } else { "/" }), - ranges - .iter() - .map(|r| [r.start(), r.end()]) - .collect::>() - ); - cmd.args(["--line-filter", filter.as_str()]); - } + let (file_name, mut args) = { + let mut args = vec![]; + let file = file + .lock() + .map_err(|e| anyhow!("Failed to lock mutex: {e:?}"))?; + let file_name = file.name.to_string_lossy().to_string(); + if !clang_params.tidy_checks.is_empty() { + args.extend(["-checks".to_string(), clang_params.tidy_checks.to_owned()]); + } + if let Some(db) = &clang_params.database { + args.extend(["-p".to_string(), db.to_string_lossy().to_string()]); + } + for arg in &clang_params.extra_args { + args.extend(["--extra-arg".to_string(), format!("\"{}\"", arg)]); + } + let ranges = file.get_ranges(&clang_params.lines_changed_only); + if !ranges.is_empty() { + let filter = format!( + "[{{\"name\":{:?},\"lines\":{:?}}}]", + &file_name.replace('/', if OS == "windows" { "\\" } else { "/" }), + ranges + .iter() + .map(|r| [r.start(), r.end()]) + .collect::>() + ); + args.extend(["--line-filter".to_string(), filter]); + } + (file_name, args) + }; let original_content = if !clang_params.tidy_review { None } else { - cmd.arg("--fix-errors"); - Some(fs::read_to_string(&file.name).with_context(|| { + args.push("--fix-errors".to_string()); + Some(fs::read_to_string(&file_name).with_context(|| { format!( "Failed to cache file's original content before applying clang-tidy changes: {}", file_name.clone() @@ -287,21 +293,24 @@ pub fn run_clang_tidy( })?) }; if !clang_params.style.is_empty() { - cmd.args(["--format-style", clang_params.style.as_str()]); + args.extend(["--format-style".to_string(), clang_params.style.to_owned()]); } - cmd.arg(file.name.to_string_lossy().as_ref()); + args.push(file_name.clone()); + let program = clang_params.clang_tidy_command.as_ref().unwrap(); + let mut cmd = Command::new(program); + cmd.args(&args); logs.push(( log::Level::Info, format!( "Running \"{} {}\"", - cmd.get_program().to_string_lossy(), - cmd.get_args() - .map(|x| x.to_string_lossy()) - .collect::>() - .join(" ") + program.to_string_lossy(), + args.join(" ") ), )); - let output = cmd.output().unwrap(); + let output = cmd + .output() + .await + .with_context(|| format!("Failed to run clang-tidy on file: {}", file_name.clone()))?; logs.push(( log::Level::Debug, format!( @@ -318,22 +327,23 @@ pub fn run_clang_tidy( ), )); } - file.tidy_advice = Some(parse_tidy_output( - &output.stdout, - &clang_params.database_json, - )?); + let mut tidy_advice = parse_tidy_output(&output.stdout, &clang_params.database_json)?; if clang_params.tidy_review { - if let Some(tidy_advice) = &mut file.tidy_advice { - // cache file changes in a buffer and restore the original contents for further analysis - tidy_advice.patched = - Some(fs::read(&file_name).with_context(|| { - format!("Failed to read changes from clang-tidy: {file_name}") - })?); - } + // cache file changes in a buffer and restore the original contents for further analysis + tidy_advice.patched = Some( + fs::read(&file_name) + .with_context(|| format!("Failed to read changes from clang-tidy: {file_name}"))?, + ); // original_content is guaranteed to be Some() value at this point fs::write(&file_name, original_content.unwrap()) .with_context(|| format!("Failed to restore file's original content: {file_name}"))?; } + { + let mut file = file + .lock() + .map_err(|e| anyhow!("Failed to lock mutex: {e:?}"))?; + file.tidy_advice = Some(tidy_advice); + } Ok(logs) } @@ -416,8 +426,8 @@ mod test { ) } - #[test] - fn use_extra_args() { + #[tokio::test] + async fn use_extra_args() { let exe_path = ClangTool::ClangTidy .get_exe_path( &RequestedVersion::from_str( @@ -443,8 +453,8 @@ mod test { clang_tidy_command: Some(exe_path), clang_format_command: None, }; - let mut file_lock = arc_file.lock().unwrap(); - let logs = run_clang_tidy(&mut file_lock, &clang_params) + let logs = run_clang_tidy(&arc_file, &clang_params) + .await .unwrap() .into_iter() .filter_map(|(_lvl, msg)| { diff --git a/cpp-linter/src/clang_tools/mod.rs b/cpp-linter/src/clang_tools/mod.rs index 5ade992..aaad9ca 100644 --- a/cpp-linter/src/clang_tools/mod.rs +++ b/cpp-linter/src/clang_tools/mod.rs @@ -6,7 +6,6 @@ use std::{ fmt::{self, Display}, fs, path::{Path, PathBuf}, - process::Command, sync::{Arc, Mutex}, }; @@ -15,7 +14,7 @@ use anyhow::{Context, Result, anyhow}; use git2::{DiffOptions, Patch}; use regex::Regex; use semver::Version; -use tokio::task::JoinSet; +use tokio::{process::Command, task::JoinSet}; use which::{which, which_in}; // project-specific modules/crates @@ -115,8 +114,8 @@ impl ClangTool { } /// Run `clang-tool --version`, then extract and return the version number. - fn capture_version(clang_tool: &PathBuf) -> Result { - let output = Command::new(clang_tool).arg("--version").output()?; + async fn capture_version(clang_tool: &PathBuf) -> Result { + let output = Command::new(clang_tool).arg("--version").output().await?; let stdout = String::from_utf8_lossy(&output.stdout); let version_pattern = Regex::new(r"(?i)version[^\d]*([\d.]+)").unwrap(); let captures = version_pattern.captures(&stdout).ok_or(anyhow!( @@ -135,29 +134,31 @@ impl ClangTool { /// 2. A collections of cached logs. A [`Vec`] of tuples that hold /// - log level /// - messages -fn analyze_single_file( +async fn analyze_single_file( file: Arc>, clang_params: Arc, ) -> Result<(PathBuf, Vec<(log::Level, String)>)> { - let mut file = file - .lock() - .map_err(|_| anyhow!("Failed to lock file mutex"))?; let mut logs = vec![]; + let file_name = { + let lock = file + .lock() + .map_err(|e| anyhow!("Failed to lock mutex: {e:?}"))?; + lock.name.to_owned() + }; if clang_params.clang_format_command.is_some() { if clang_params .format_filter .as_ref() - .is_some_and(|f| f.is_source_or_ignored(file.name.as_path())) - || clang_params.format_filter.is_none() + .is_none_or(|f| f.is_source_or_ignored(file_name.as_path())) { - let format_result = run_clang_format(&mut file, &clang_params)?; + let format_result = run_clang_format(&file, &clang_params).await?; logs.extend(format_result); } else { logs.push(( log::Level::Info, format!( "{} not scanned by clang-format due to `--ignore-format`", - file.name.as_os_str().to_string_lossy() + file_name.as_os_str().to_string_lossy() ), )); } @@ -166,22 +167,21 @@ fn analyze_single_file( if clang_params .tidy_filter .as_ref() - .is_some_and(|f| f.is_source_or_ignored(file.name.as_path())) - || clang_params.tidy_filter.is_none() + .is_none_or(|f| f.is_source_or_ignored(file_name.as_path())) { - let tidy_result = run_clang_tidy(&mut file, &clang_params)?; + let tidy_result = run_clang_tidy(&file, &clang_params).await?; logs.extend(tidy_result); } else { logs.push(( log::Level::Info, format!( "{} not scanned by clang-tidy due to `--ignore-tidy`", - file.name.as_os_str().to_string_lossy() + file_name.as_os_str().to_string_lossy() ), )); } } - Ok((file.name.clone(), logs)) + Ok((file_name, logs)) } /// A struct to contain the version numbers of the clang-tools used @@ -209,7 +209,7 @@ pub async fn capture_clang_tools_output( // info as debugging output. if clang_params.tidy_checks != "-*" { let exe_path = ClangTool::ClangTidy.get_exe_path(version)?; - let version_found = ClangTool::capture_version(&exe_path)?; + let version_found = ClangTool::capture_version(&exe_path).await?; log::debug!( "{} --version: v{version_found}", &exe_path.to_string_lossy() @@ -219,7 +219,7 @@ pub async fn capture_clang_tools_output( } if !clang_params.style.is_empty() { let exe_path = ClangTool::ClangFormat.get_exe_path(version)?; - let version_found = ClangTool::capture_version(&exe_path)?; + let version_found = ClangTool::capture_version(&exe_path).await?; log::debug!( "{} --version: v{version_found}", &exe_path.to_string_lossy() @@ -243,9 +243,8 @@ pub async fn capture_clang_tools_output( let arc_params = Arc::new(clang_params); // iterate over the discovered files and run the clang tools for file in files { - let arc_file = file.clone(); - let arc_params = arc_params.clone(); - executors.spawn(async move { analyze_single_file(arc_file, arc_params) }); + let arc_file = Arc::clone(file); + executors.spawn(analyze_single_file(arc_file, arc_params.clone())); } while let Some(output) = executors.join_next().await { diff --git a/uv.lock b/uv.lock index 9c3cebd..9a81167 100644 --- a/uv.lock +++ b/uv.lock @@ -23,16 +23,16 @@ wheels = [ [[package]] name = "backrefs" -version = "6.0.1" +version = "6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/91/e6/5eac48095081c358926a0cd8821351d7a013168b05cad9530fa3bcae3071/backrefs-6.0.1.tar.gz", hash = "sha256:54f8453c9ae38417a83c06d23745c634138c8da622d87a12cb3eef9ba66dd466", size = 5767249, upload-time = "2025-07-30T02:51:32.816Z" } +sdist = { url = "https://files.pythonhosted.org/packages/86/e3/bb3a439d5cb255c4774724810ad8073830fac9c9dee123555820c1bcc806/backrefs-6.1.tar.gz", hash = "sha256:3bba1749aafe1db9b915f00e0dd166cba613b6f788ffd63060ac3485dc9be231", size = 7011962, upload-time = "2025-11-15T14:52:08.323Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/03/c9/482590c6e687e8e962d6446c5279a4b5f498c31dd0352352e106af6fd1d7/backrefs-6.0.1-py310-none-any.whl", hash = "sha256:78a69e21b71d739b625b52b5adbf7eb1716fb4cf0a39833826f59546f321cb99", size = 381119, upload-time = "2025-07-30T02:51:21.376Z" }, - { url = "https://files.pythonhosted.org/packages/3d/ca/7476846268a6382f0e7535fecedf81b514bdeae1404d2866040e1ec21ae3/backrefs-6.0.1-py311-none-any.whl", hash = "sha256:6ba76d616ccb02479a3a098ad1f46d92225f280d7bdce7583bc62897f32d946c", size = 392915, upload-time = "2025-07-30T02:51:23.311Z" }, - { url = "https://files.pythonhosted.org/packages/65/68/349b7d6d646d36d00aca3fd9c80082ec8991138b74046afb1895235f4ae9/backrefs-6.0.1-py312-none-any.whl", hash = "sha256:2f440f79f5ef5b9083fd366a09a976690044eca0ea0e59ac0508c3630e0ebc7c", size = 398827, upload-time = "2025-07-30T02:51:24.741Z" }, - { url = "https://files.pythonhosted.org/packages/a7/45/84853f5ce1182cc283beebd0a7f05e4210aac06b4f39192cefd60e5901b1/backrefs-6.0.1-py313-none-any.whl", hash = "sha256:62ea7e9b286808576f35b2d28a0daa09b85ae2fc71b82a951d35729b0138e66b", size = 400784, upload-time = "2025-07-30T02:51:26.577Z" }, - { url = "https://files.pythonhosted.org/packages/cb/07/2e43935cbaa0ec12d7e225e942a3c1e39fc8233f7b18100bcbffd25e6192/backrefs-6.0.1-py314-none-any.whl", hash = "sha256:3ba0d943178d24a3721c5d915734767fa93f3bde1d317c4ef9e0f33b21b9c302", size = 412645, upload-time = "2025-07-30T02:51:28.521Z" }, - { url = "https://files.pythonhosted.org/packages/e2/9b/14e312dbbc994093caa942a3462dc9f5f54bd0770c8171c6f6aec06e8600/backrefs-6.0.1-py39-none-any.whl", hash = "sha256:b1a61b29c35cc72cfb54886164b626fbe64cab74e9d8dcac125155bd3acdb023", size = 381118, upload-time = "2025-07-30T02:51:30.749Z" }, + { url = "https://files.pythonhosted.org/packages/3b/ee/c216d52f58ea75b5e1841022bbae24438b19834a29b163cb32aa3a2a7c6e/backrefs-6.1-py310-none-any.whl", hash = "sha256:2a2ccb96302337ce61ee4717ceacfbf26ba4efb1d55af86564b8bbaeda39cac1", size = 381059, upload-time = "2025-11-15T14:51:59.758Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9a/8da246d988ded941da96c7ed945d63e94a445637eaad985a0ed88787cb89/backrefs-6.1-py311-none-any.whl", hash = "sha256:e82bba3875ee4430f4de4b6db19429a27275d95a5f3773c57e9e18abc23fd2b7", size = 392854, upload-time = "2025-11-15T14:52:01.194Z" }, + { url = "https://files.pythonhosted.org/packages/37/c9/fd117a6f9300c62bbc33bc337fd2b3c6bfe28b6e9701de336b52d7a797ad/backrefs-6.1-py312-none-any.whl", hash = "sha256:c64698c8d2269343d88947c0735cb4b78745bd3ba590e10313fbf3f78c34da5a", size = 398770, upload-time = "2025-11-15T14:52:02.584Z" }, + { url = "https://files.pythonhosted.org/packages/eb/95/7118e935b0b0bd3f94dfec2d852fd4e4f4f9757bdb49850519acd245cd3a/backrefs-6.1-py313-none-any.whl", hash = "sha256:4c9d3dc1e2e558965202c012304f33d4e0e477e1c103663fd2c3cc9bb18b0d05", size = 400726, upload-time = "2025-11-15T14:52:04.093Z" }, + { url = "https://files.pythonhosted.org/packages/1d/72/6296bad135bfafd3254ae3648cd152980a424bd6fed64a101af00cc7ba31/backrefs-6.1-py314-none-any.whl", hash = "sha256:13eafbc9ccd5222e9c1f0bec563e6d2a6d21514962f11e7fc79872fd56cbc853", size = 412584, upload-time = "2025-11-15T14:52:05.233Z" }, + { url = "https://files.pythonhosted.org/packages/02/e3/a4fa1946722c4c7b063cc25043a12d9ce9b4323777f89643be74cef2993c/backrefs-6.1-py39-none-any.whl", hash = "sha256:a9e99b8a4867852cad177a6430e31b0f6e495d65f8c6c134b68c14c3c95bf4b0", size = 381058, upload-time = "2025-11-15T14:52:06.698Z" }, ] [[package]] @@ -57,11 +57,26 @@ wheels = [ name = "cfgv" version = "3.4.0" source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.10'", +] sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, ] +[[package]] +name = "cfgv" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", +] +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, +] + [[package]] name = "charset-normalizer" version = "3.4.4" @@ -222,7 +237,7 @@ wheels = [ [[package]] name = "click" -version = "8.3.0" +version = "8.3.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.10'", @@ -230,9 +245,9 @@ resolution-markers = [ dependencies = [ { name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" }, + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, ] [[package]] @@ -254,7 +269,7 @@ dev = [ { name = "mypy" }, { name = "patchelf", marker = "sys_platform == 'linux'" }, { name = "pre-commit", version = "4.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "pre-commit", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pre-commit", version = "4.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "ruff" }, ] test = [ @@ -533,6 +548,7 @@ wheels = [ name = "meson" version = "1.9.1" source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/48/d8/6c1dd1c740b7d5fd73a6ad67900a09e3dd6642013f58fa9e22ae6faaffc7/meson-1.9.1.tar.gz", hash = "sha256:4e076606f2afff7881d195574bddcd8d89286f35a17b4977a216f535dc0c74ac", size = 5083044, upload-time = "2025-11-13T00:38:38.509Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/9c/07/b48592d325cb86682829f05216e4efb2dc881762b8f1bafb48b57442307a/meson-1.9.1-py3-none-any.whl", hash = "sha256:f824ab770c041a202f532f69e114c971918ed2daff7ea56583d80642564598d0", size = 1030356, upload-time = "2025-09-22T18:39:37.458Z" }, ] @@ -543,7 +559,7 @@ version = "1.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "click", version = "8.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "click", version = "8.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "ghp-import" }, { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, @@ -584,7 +600,7 @@ dependencies = [ { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, { name = "mergedeep" }, { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "platformdirs", version = "4.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "platformdirs", version = "4.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "pyyaml" }, ] sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239, upload-time = "2023-11-20T17:51:09.981Z" } @@ -761,14 +777,14 @@ wheels = [ [[package]] name = "platformdirs" -version = "4.5.0" +version = "4.5.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.10'", ] -sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" }, + { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, ] [[package]] @@ -779,7 +795,7 @@ resolution-markers = [ "python_full_version < '3.10'", ] dependencies = [ - { name = "cfgv", marker = "python_full_version < '3.10'" }, + { name = "cfgv", version = "3.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "identify", marker = "python_full_version < '3.10'" }, { name = "nodeenv", marker = "python_full_version < '3.10'" }, { name = "pyyaml", marker = "python_full_version < '3.10'" }, @@ -792,21 +808,21 @@ wheels = [ [[package]] name = "pre-commit" -version = "4.4.0" +version = "4.5.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "cfgv", marker = "python_full_version >= '3.10'" }, + { name = "cfgv", version = "3.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "identify", marker = "python_full_version >= '3.10'" }, { name = "nodeenv", marker = "python_full_version >= '3.10'" }, { name = "pyyaml", marker = "python_full_version >= '3.10'" }, { name = "virtualenv", marker = "python_full_version >= '3.10'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/49/7845c2d7bf6474efd8e27905b51b11e6ce411708c91e829b93f324de9929/pre_commit-4.4.0.tar.gz", hash = "sha256:f0233ebab440e9f17cabbb558706eb173d19ace965c68cdce2c081042b4fab15", size = 197501, upload-time = "2025-11-08T21:12:11.607Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f4/9b/6a4ffb4ed980519da959e1cf3122fc6cb41211daa58dbae1c73c0e519a37/pre_commit-4.5.0.tar.gz", hash = "sha256:dc5a065e932b19fc1d4c653c6939068fe54325af8e741e74e88db4d28a4dd66b", size = 198428, upload-time = "2025-11-22T21:02:42.304Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/27/11/574fe7d13acf30bfd0a8dd7fa1647040f2b8064f13f43e8c963b1e65093b/pre_commit-4.4.0-py2.py3-none-any.whl", hash = "sha256:b35ea52957cbf83dcc5d8ee636cbead8624e3a15fbfa61a370e42158ac8a5813", size = 226049, upload-time = "2025-11-08T21:12:10.228Z" }, + { url = "https://files.pythonhosted.org/packages/5d/c4/b2d28e9d2edf4f1713eb3c29307f1a63f3d67cf09bdda29715a36a68921a/pre_commit-4.5.0-py2.py3-none-any.whl", hash = "sha256:25e2ce09595174d9c97860a95609f9f852c0614ba602de3561e267547f2335e1", size = 226429, upload-time = "2025-11-22T21:02:40.836Z" }, ] [[package]] @@ -820,16 +836,16 @@ wheels = [ [[package]] name = "pymdown-extensions" -version = "10.17.1" +version = "10.18" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "markdown", version = "3.10", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e7/d9/a987e4d549c6c82353fce5fa5f650229bb60ea4c0d1684a2714a509aef58/pymdown_extensions-10.17.1.tar.gz", hash = "sha256:60d05fe55e7fb5a1e4740fc575facad20dc6ee3a748e8d3d36ba44142e75ce03", size = 845207, upload-time = "2025-11-11T21:44:58.815Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/95/e4fa281e3f13b3d9c4aaebb21ef44879840325fa418276dd921209a5e9f9/pymdown_extensions-10.18.tar.gz", hash = "sha256:20252abe6367354b24191431617a072ee6be9f68c5afcc74ea5573508a61f9e5", size = 847697, upload-time = "2025-12-07T17:22:12.857Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/40/b2d7b9fdccc63e48ae4dbd363b6b89eb7ac346ea49ed667bb71f92af3021/pymdown_extensions-10.17.1-py3-none-any.whl", hash = "sha256:1f160209c82eecbb5d8a0d8f89a4d9bd6bdcbde9a8537761844cfc57ad5cd8a6", size = 266310, upload-time = "2025-11-11T21:44:56.809Z" }, + { url = "https://files.pythonhosted.org/packages/46/a4/aa2bada4a2fd648f40f19affa55d2c01dc7ff5ea9cffd3dfdeb6114951db/pymdown_extensions-10.18-py3-none-any.whl", hash = "sha256:090bca72be43f7d3186374e23c782899dbef9dc153ef24c59dcd3c346f9ffcae", size = 266703, upload-time = "2025-12-07T17:22:11.22Z" }, ] [[package]] @@ -1039,11 +1055,11 @@ wheels = [ [[package]] name = "urllib3" -version = "2.5.0" +version = "2.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/43/554c2569b62f49350597348fc3ac70f786e3c32e7f19d266e19817812dd3/urllib3-2.6.0.tar.gz", hash = "sha256:cb9bcef5a4b345d5da5d145dc3e30834f58e8018828cbc724d30b4cb7d4d49f1", size = 432585, upload-time = "2025-12-05T15:08:47.885Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, + { url = "https://files.pythonhosted.org/packages/56/1a/9ffe814d317c5224166b23e7c47f606d6e473712a2fad0f704ea9b99f246/urllib3-2.6.0-py3-none-any.whl", hash = "sha256:c90f7a39f716c572c4e3e58509581ebd83f9b59cced005b7db7ad2d22b0db99f", size = 131083, upload-time = "2025-12-05T15:08:45.983Z" }, ] [[package]] @@ -1055,7 +1071,7 @@ dependencies = [ { name = "filelock", version = "3.19.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "filelock", version = "3.20.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "platformdirs", version = "4.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "platformdirs", version = "4.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799, upload-time = "2025-10-29T06:57:40.511Z" }