use crate::paths;
use crate::quilt::flow::browse::cache_remote_manifest;
use crate::quilt::lineage::DomainLineage;
use crate::quilt::lineage::PackageLineage;
use crate::quilt::manifest_handle::RemoteManifest;
use crate::quilt::remote::Remote;
use crate::quilt::Storage;
use crate::Error;
pub async fn install_package(
lineage: DomainLineage,
paths: &paths::DomainPaths,
storage: &(impl Storage + Sync),
remote: &impl Remote,
remote_manifest: &RemoteManifest,
) -> Result<DomainLineage, Error> {
if lineage.packages.contains_key(&remote_manifest.namespace) {
return Err(Error::PackageAlreadyInstalled(
remote_manifest.namespace.clone(),
));
}
cache_remote_manifest(paths, storage, remote, remote_manifest).await?;
let installed_manifest_path =
paths.installed_manifest(&remote_manifest.namespace, &remote_manifest.hash);
storage
.create_dir_all(&installed_manifest_path.parent().unwrap())
.await?;
paths::copy_cached_to_installed(
paths,
storage,
&remote_manifest.bucket,
&remote_manifest.namespace,
&remote_manifest.hash,
)
.await?;
let objects_dir = paths.objects_dir();
storage.create_dir_all(&objects_dir).await?;
let working_dir = paths.working_dir(&remote_manifest.namespace);
storage.create_dir_all(&working_dir).await?;
let latest_hash = remote_manifest.resolve_latest(remote).await?;
let mut lineage = lineage;
lineage.packages.insert(
remote_manifest.namespace.clone(),
PackageLineage::from_remote(remote_manifest.to_owned(), latest_hash),
);
Ok(lineage)
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeMap;
use std::path::PathBuf;
use crate::quilt::remote::mock_remote::MockRemote;
use crate::quilt::storage::mock_storage::MockStorage;
use crate::quilt::storage::s3::S3Uri;
#[tokio::test]
async fn test_if_already_installed() -> Result<(), Error> {
let lineage = DomainLineage {
packages: BTreeMap::from([("foo".to_string(), PackageLineage::default())]),
};
let result = install_package(
lineage,
&paths::DomainPaths::default(),
&MockStorage::default(),
&MockRemote::default(),
&RemoteManifest {
namespace: "foo".to_string(),
..RemoteManifest::default()
},
)
.await;
assert_eq!(
result.unwrap_err().to_string(),
"The package foo is already installed"
);
Ok(())
}
#[tokio::test]
async fn test_installing() -> Result<(), Error> {
let remote_manifest = RemoteManifest {
bucket: "a".to_string(),
hash: "c".to_string(),
namespace: "b".to_string(),
};
let remote = MockRemote::default();
remote
.put_object(
&S3Uri::try_from("s3://a/.quilt/packages/1220c.parquet")?,
Vec::new(),
)
.await?;
remote
.put_object(
&S3Uri::try_from("s3://a/.quilt/named_packages/b/latest")?,
Vec::new(),
)
.await?;
let storage = MockStorage::default();
let result = install_package(
DomainLineage::default(),
&paths::DomainPaths::default(),
&storage,
&remote,
&remote_manifest,
)
.await?;
assert_eq!(result.packages.get("b").unwrap().remote, remote_manifest);
assert!(storage.exists(&PathBuf::from(".quilt/installed/b/c")).await);
assert!(storage.exists(&PathBuf::from(".quilt/packages/a/c")).await);
Ok(())
}
}