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
use anyhow::Context;
use webc::compat::Container;

use crate::runtime::resolver::{
    DistributionInfo, PackageInfo, PackageSpecifier, PackageSummary, QueryError, Source, WebcHash,
};

/// A [`Source`] that knows how to query files on the filesystem.
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct FileSystemSource {}

#[async_trait::async_trait]
impl Source for FileSystemSource {
    #[tracing::instrument(level = "debug", skip_all, fields(%package))]
    async fn query(&self, package: &PackageSpecifier) -> Result<Vec<PackageSummary>, QueryError> {
        let path = match package {
            PackageSpecifier::Path(path) => path.canonicalize().with_context(|| {
                format!(
                    "Unable to get the canonical form for \"{}\"",
                    path.display()
                )
            })?,
            _ => return Err(QueryError::Unsupported),
        };

        // FIXME: These two operations will block
        let webc_sha256 = WebcHash::for_file(&path)
            .with_context(|| format!("Unable to hash \"{}\"", path.display()))?;
        let container = Container::from_disk(&path)
            .with_context(|| format!("Unable to parse \"{}\"", path.display()))?;

        let url = crate::runtime::resolver::utils::url_from_file_path(&path)
            .ok_or_else(|| anyhow::anyhow!("Unable to turn \"{}\" into a URL", path.display()))?;

        let pkg = PackageInfo::from_manifest(container.manifest())
            .context("Unable to determine the package's metadata")?;
        let summary = PackageSummary {
            pkg,
            dist: DistributionInfo {
                webc: url,
                webc_sha256,
            },
        };

        Ok(vec![summary])
    }
}