posthog_cli/utils/
files.rs1use anyhow::{Context, Result};
2use sha2::Digest;
3use std::path::PathBuf;
4use walkdir::DirEntry;
5
6use crate::sourcemaps::source_pair::SourceMapContent;
7
8pub struct SourceFile<T: SourceContent> {
9 pub path: PathBuf,
10 pub content: T,
11}
12
13impl<T: SourceContent> SourceFile<T> {
14 pub fn new(path: PathBuf, content: T) -> Self {
15 SourceFile { path, content }
16 }
17
18 pub fn load(path: &PathBuf) -> Result<Self> {
19 let content = std::fs::read(path)?;
20 Ok(SourceFile::new(path.clone(), T::parse(content)?))
21 }
22
23 pub fn save(&self, dest: Option<PathBuf>) -> Result<()> {
25 let final_path = dest.unwrap_or(self.path.clone());
26 std::fs::write(&final_path, &self.content.serialize()?)?;
27 Ok(())
28 }
29}
30
31pub trait SourceContent {
32 fn parse(content: Vec<u8>) -> Result<Self>
33 where
34 Self: Sized;
35
36 fn serialize(&self) -> Result<Vec<u8>>;
37}
38
39impl SourceContent for String {
40 fn parse(content: Vec<u8>) -> Result<Self> {
41 Ok(String::from_utf8(content)?)
42 }
43
44 fn serialize(&self) -> Result<Vec<u8>> {
45 Ok(self.clone().into_bytes())
46 }
47}
48
49impl SourceContent for SourceMapContent {
50 fn parse(content: Vec<u8>) -> Result<Self> {
51 Ok(serde_json::from_slice(&content)?)
52 }
53
54 fn serialize(&self) -> Result<Vec<u8>> {
55 Ok(serde_json::to_vec(self)?)
56 }
57}
58
59impl SourceContent for Vec<u8> {
60 fn parse(content: Vec<u8>) -> Result<Self> {
61 Ok(content)
62 }
63
64 fn serialize(&self) -> Result<Vec<u8>> {
65 Ok(self.clone())
66 }
67}
68
69pub fn delete_files(paths: Vec<PathBuf>) -> Result<()> {
70 for path in paths {
72 if path.exists() {
73 std::fs::remove_file(&path)
74 .context(format!("Failed to delete file: {}", path.display()))?;
75 }
76 }
77 Ok(())
78}
79
80pub fn content_hash<Iter, Item: AsRef<[u8]>>(upload_data: Iter) -> String
83where
84 Iter: IntoIterator<Item = Item>,
85{
86 let mut hasher = sha2::Sha512::new();
87 for data in upload_data {
88 hasher.update(data.as_ref());
89 }
90 format!("{:x}", hasher.finalize())
91}
92
93pub fn is_javascript_file(entry: &DirEntry) -> bool {
94 entry.file_type().is_file()
95 && entry
96 .path()
97 .extension()
98 .is_some_and(|ext| ext == "js" || ext == "mjs" || ext == "cjs")
99}