1use anyhow::Result;
4use regex::Regex;
5use sha2::{Digest, Sha256};
6use std::time::{SystemTime, UNIX_EPOCH};
7
8#[inline]
10pub fn current_timestamp() -> u64 {
11 SystemTime::now()
12 .duration_since(UNIX_EPOCH)
13 .expect("System time is before Unix epoch")
14 .as_secs()
15}
16
17pub fn calculate_sha256(content: &[u8]) -> String {
19 let mut hasher = Sha256::new();
20 hasher.update(content);
21 format!("{:x}", hasher.finalize())
22}
23
24pub fn extract_toml_str(content: &str, key: &str) -> Option<String> {
26 let pkg_section = if let Some(start) = content.find("[package]") {
28 let rest = &content[start + "[package]".len()..];
29 if let Some(_next) = rest.find('\n') {
31 &content[start..]
32 } else {
33 &content[start..]
34 }
35 } else {
36 content
37 };
38
39 let pattern = format!(r#"(?m)^\s*{}\s*=\s*"([^"]+)"\s*$"#, regex::escape(key));
41 let re = Regex::new(&pattern).ok()?;
42 re.captures(pkg_section)
43 .and_then(|caps| caps.get(1).map(|m| m.as_str().to_owned()))
44}
45
46pub fn extract_readme_excerpt(md: &str, max_len: usize) -> String {
48 let mut excerpt = String::new();
50 for line in md.lines() {
51 if excerpt.len() > max_len {
53 break;
54 }
55 excerpt.push_str(line);
56 excerpt.push('\n');
57 if line.trim().starts_with("## ") && excerpt.len() > (max_len / 2) {
59 break;
60 }
61 }
62 if excerpt.len() > max_len {
63 excerpt.truncate(max_len);
64 excerpt.push_str("...\n");
65 }
66 excerpt
67}
68
69pub fn safe_replace_text(content: &str, old_str: &str, new_str: &str) -> Result<String> {
71 if old_str.is_empty() {
72 return Err(anyhow::anyhow!("old_string cannot be empty"));
73 }
74
75 if !content.contains(old_str) {
76 return Err(anyhow::anyhow!("Text '{}' not found in content", old_str));
77 }
78
79 Ok(content.replace(old_str, new_str))
80}