summaryrefslogtreecommitdiffstats
path: root/src/filestore/path.rs
blob: 80cd0438afe4a1bc28daf7a1fa45041e7390983a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use std::path::Path;
use std::path::PathBuf;
use std::ffi::OsStr;

use anyhow::anyhow;
use anyhow::Error;
use anyhow::Result;
use anyhow::Context;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StoreRoot(PathBuf);

impl StoreRoot {
    pub fn new(root: PathBuf) -> Result<Self> {
        if root.is_absolute() {
            if root.is_dir() {
                Ok(StoreRoot(root))
            } else {
                Err(anyhow!("StoreRoot path does not point to directory: {}", root.display()))
            }
        } else {
            Err(anyhow!("StoreRoot path is not absolute: {}", root.display()))
        }
    }

    pub (in crate::filestore) fn stripped_from(&self, pb: &Path) -> Result<ArtifactPath> {
        pb.strip_prefix(&self.0)
            .map_err(Error::from)
            .and_then(|p| ArtifactPath::new(p.to_path_buf()))
    }

    pub fn join<'a>(&'a self, ap: &'a ArtifactPath) -> FullArtifactPath<'a> {
        FullArtifactPath(&self, ap)
    }

    pub fn is_file(&self, subpath: &Path) -> bool {
        self.0.join(subpath).is_file()
    }

    pub fn is_dir(&self, subpath: &Path) -> bool {
        self.0.join(subpath).is_dir()
    }

    pub fn display(&self) -> std::path::Display {
        self.0.display()
    }

    pub (in crate::filestore) fn walk(&self) -> walkdir::WalkDir {
        walkdir::WalkDir::new(&self.0)
    }
}

impl AsRef<Path> for StoreRoot {
    fn as_ref(&self) -> &Path {
        &self.0
    }
}


#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct ArtifactPath(PathBuf);

impl ArtifactPath {
    pub (in crate::filestore) fn new(p: PathBuf) -> Result<Self> {
        if p.is_relative() {
            Ok(ArtifactPath(p))
        } else {
            Err(anyhow!("Path is not relative: {}", p.display()))
        }
    }

    pub fn display(&self) -> std::path::Display {
        self.0.display()
    }

    pub fn file_name(&self) -> Option<&OsStr> {
        self.0.file_name()
    }

    pub fn to_str(&self) -> Option<&str> {
        self.0.to_str()
    }

    pub (in crate::filestore) fn file_stem(&self) -> Option<&OsStr> {
        self.0.file_stem()
    }

    pub (in crate::filestore) fn is_dir(&self) -> bool {
        self.0.is_dir()
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FullArtifactPath<'a>(&'a StoreRoot, &'a ArtifactPath);

impl<'a> FullArtifactPath<'a> {
    fn joined(&self) -> PathBuf {
        self.0.0.join(&self.1.0)
    }

    pub (in crate::filestore) fn is_file(&self) -> bool {
        self.joined().is_file()
    }

    pub fn display(&self) -> FullArtifactPathDisplay<'a> {
        FullArtifactPathDisplay(self.0, self.1)
    }

    pub async fn read(self) -> Result<Vec<u8>> {
        tokio::fs::read(self.joined())
            .await
            .map(Vec::from)
            .with_context(|| anyhow!("Reading artifact from path {}", self.0.display()))
            .map_err(Error::from)
    }
}

pub struct FullArtifactPathDisplay<'a>(&'a StoreRoot, &'a ArtifactPath);

impl<'a> std::fmt::Display for FullArtifactPathDisplay<'a> {
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(fmt, "{}/{}", self.0.display(), self.1.display())
    }
}