rocketmq_runtime/common/
file_utils.rs1use std::io::{self};
16use std::path::Path;
17
18use crate::LocalMetadataFileSystem;
19use crate::MetadataFileSystem;
20use crate::RuntimeError;
21use crate::RuntimeOperation;
22use crate::RuntimeResult;
23use parking_lot::Mutex;
24use tracing::warn;
25
26static LOCK: Mutex<()> = Mutex::new(());
27
28pub fn file_to_string(file_name: impl AsRef<Path>) -> RuntimeResult<String> {
30 let path = file_name.as_ref();
31 match std::fs::read_to_string(path) {
32 Ok(sr) => Ok(sr),
33 Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
34 warn!("file not exist: {}", path.display());
35 Ok(String::new())
36 }
37 Err(e) => Err(RuntimeError::io(RuntimeOperation::ReadFile, e)),
38 }
39}
40pub fn string_to_file(str_content: &str, file_name: impl AsRef<Path>) -> RuntimeResult<()> {
56 let _lock = LOCK.lock();
57
58 let file_path = file_name.as_ref();
59 let mut bak_file = file_path.as_os_str().to_os_string();
60 bak_file.push(".bak");
61
62 if file_path.exists() {
64 let previous =
65 std::fs::read(file_path).map_err(|error| RuntimeError::io(RuntimeOperation::ReadFileBackup, error))?;
66 LocalMetadataFileSystem
67 .persist_atomic(Path::new(&bak_file), &previous)
68 .map_err(metadata_io_error)?;
69 }
70
71 LocalMetadataFileSystem
72 .persist_atomic(file_path, str_content.as_bytes())
73 .map_err(metadata_io_error)
74}
75
76pub fn metadata_io_error(error: impl std::error::Error + Send + Sync + 'static) -> RuntimeError {
78 RuntimeError::internal(RuntimeOperation::PersistMetadata, error)
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn test_file_to_string() {
87 let temp_file = tempfile::NamedTempFile::new().unwrap();
89 let file_path = temp_file.path().to_str().unwrap();
90
91 let content = "Hello, World!";
93 std::fs::write(file_path, content).unwrap();
94
95 let result = file_to_string(file_path);
97
98 assert!(result.is_ok());
100 assert_eq!(result.unwrap(), content);
101 }
102
103 #[test]
104 fn test_string_to_file() {
105 let temp_file = tempfile::NamedTempFile::new().unwrap();
107 let file_path = temp_file.path().to_str().unwrap();
108
109 let content = "Hello, World!";
111 let result = string_to_file(content, file_path);
112
113 assert!(result.is_ok());
115 assert_eq!(std::fs::read_to_string(file_path).unwrap(), content);
116 }
117
118 #[test]
119 fn replacing_a_file_keeps_the_previous_content_as_a_backup() {
120 let directory = tempfile::tempdir().unwrap();
121 let file_path = directory.path().join("config.json");
122 let backup_path = directory.path().join("config.json.bak");
123
124 string_to_file("first", &file_path).unwrap();
125 assert!(!backup_path.exists(), "a new file has no previous content to keep");
126
127 string_to_file("second", &file_path).unwrap();
128 assert_eq!(std::fs::read_to_string(&file_path).unwrap(), "second");
129 assert_eq!(std::fs::read_to_string(&backup_path).unwrap(), "first");
130 }
131
132 #[test]
133 fn test_file_to_string_not_found() {
134 let result = file_to_string("/nonexistent/path/file.txt");
135 assert!(result.is_ok());
136 assert_eq!(result.unwrap(), "");
137 }
138}