glory_cli/ext/
fs.rs

1use crate::ext::anyhow::{Context, Result};
2use camino::{Utf8Path, Utf8PathBuf};
3use std::{collections::VecDeque, path::Path};
4use tokio::fs::{self, ReadDir};
5
6use super::path::PathExt;
7
8pub async fn rm_dir_content<P: AsRef<Path>>(dir: P) -> Result<()> {
9    try_rm_dir_content(&dir)
10        .await
11        .context(format!("Could not remove contents of {:?}", dir.as_ref()))
12}
13
14async fn try_rm_dir_content<P: AsRef<Path>>(dir: P) -> Result<()> {
15    let dir = dir.as_ref();
16
17    if !dir.exists() {
18        log::debug!("Glory not cleaning {dir:?} because it does not exist");
19        return Ok(());
20    }
21
22    let mut entries = self::read_dir(dir).await?;
23    while let Some(entry) = entries.next_entry().await? {
24        let path = entry.path();
25
26        if entry.file_type().await?.is_dir() {
27            self::remove_dir_all(path).await?;
28        } else {
29            self::remove_file(path).await?;
30        }
31    }
32    Ok(())
33}
34
35pub async fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> {
36    fs::write(&path, contents)
37        .await
38        .context(format!("Could not write to {:?}", path.as_ref()))
39}
40
41pub async fn read(path: impl AsRef<Path>) -> Result<Vec<u8>> {
42    fs::read(&path).await.context(format!("Could not read {:?}", path.as_ref()))
43}
44
45pub async fn create_dir(path: impl AsRef<Path>) -> Result<()> {
46    log::trace!("FS create_dir {:?}", path.as_ref());
47    fs::create_dir(&path).await.context(format!("Could not create dir {:?}", path.as_ref()))
48}
49
50pub async fn create_dir_all<P: AsRef<Path>>(path: P) -> Result<()> {
51    log::trace!("FS create_dir_all {:?}", path.as_ref());
52    fs::create_dir_all(&path).await.context(format!("Could not create {:?}", path.as_ref()))
53}
54pub async fn read_to_string<P: AsRef<Path>>(path: P) -> Result<String> {
55    fs::read_to_string(&path)
56        .await
57        .context(format!("Could not read to string {:?}", path.as_ref()))
58}
59
60pub async fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<u64> {
61    fs::copy(&from, &to)
62        .await
63        .context(format!("copy {:?} to {:?}", from.as_ref(), to.as_ref()))
64}
65
66pub async fn read_dir<P: AsRef<Path>>(path: P) -> Result<ReadDir> {
67    fs::read_dir(&path).await.context(format!("Could not read dir {:?}", path.as_ref()))
68}
69
70pub async fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {
71    fs::rename(&from, &to)
72        .await
73        .context(format!("Could not rename from {:?} to {:?}", from.as_ref(), to.as_ref()))
74}
75
76pub async fn remove_file<P: AsRef<Path>>(path: P) -> Result<()> {
77    fs::remove_file(&path).await.context(format!("Could not remove file {:?}", path.as_ref()))
78}
79
80#[allow(dead_code)]
81pub async fn remove_dir<P: AsRef<Path>>(path: P) -> Result<()> {
82    fs::remove_dir(&path).await.context(format!("Could not remove dir {:?}", path.as_ref()))
83}
84
85pub async fn remove_dir_all<P: AsRef<Path>>(path: P) -> Result<()> {
86    fs::remove_dir_all(&path)
87        .await
88        .context(format!("Could not remove dir {:?}", path.as_ref()))
89}
90
91pub async fn copy_dir_all(src: impl AsRef<Utf8Path>, dst: impl AsRef<Path>) -> Result<()> {
92    cp_dir_all(&src, &dst)
93        .await
94        .context(format!("Copy dir recursively from {:?} to {:?}", src.as_ref(), dst.as_ref()))
95}
96
97async fn cp_dir_all(src: impl AsRef<Utf8Path>, dst: impl AsRef<Path>) -> Result<()> {
98    let src = src.as_ref();
99    let dst = Utf8PathBuf::from_path_buf(dst.as_ref().to_path_buf()).unwrap();
100
101    self::create_dir_all(&dst).await?;
102
103    let mut dirs = VecDeque::new();
104    dirs.push_back(src.to_owned());
105
106    while let Some(dir) = dirs.pop_front() {
107        let mut entries = dir.read_dir_utf8()?;
108
109        while let Some(Ok(entry)) = entries.next() {
110            let from = entry.path().to_owned();
111            let to = from.rebase(src, &dst)?;
112
113            if entry.file_type()?.is_dir() {
114                self::create_dir(&to).await?;
115                dirs.push_back(from);
116            } else {
117                self::copy(from, to).await?;
118            }
119        }
120    }
121    Ok(())
122}