use std::fs;
use std::path::{Path, PathBuf};
use storage::{Backend, CachedBackend, Component};
use core::{CliError, LalResult, output};
fn is_cached<T: Backend + ?Sized>(backend: &T, name: &str, version: u32, env: &str) -> bool {
get_cache_dir(backend, name, version, env).is_dir()
}
fn get_cache_dir<T: Backend + ?Sized>(backend: &T, name: &str, version: u32, env: &str) -> PathBuf {
let cache = backend.get_cache_dir();
Path::new(&cache).join("environments").join(env).join(name).join(version.to_string())
}
fn store_tarball<T: Backend + ?Sized>(
backend: &T,
name: &str,
version: u32,
env: &str,
) -> Result<(), CliError> {
let destdir = get_cache_dir(backend, name, version, env);
if !destdir.is_dir() {
fs::create_dir_all(&destdir)?;
}
let tarname = [name, ".tar"].concat();
let dest = Path::new(&destdir).join(&tarname);
let src = Path::new(".").join(&tarname);
if !src.is_file() {
return Err(CliError::MissingTarball);
}
debug!("Move {:?} -> {:?}", src, dest);
fs::copy(&src, &dest)?;
fs::remove_file(&src)?;
Ok(())
}
fn extract_tarball_to_input(tarname: PathBuf, component: &str) -> LalResult<()> {
use tar::Archive;
use flate2::read::GzDecoder;
let extract_path = Path::new("./INPUT").join(component);
let _ = fs::remove_dir_all(&extract_path); fs::create_dir_all(&extract_path)?;
if cfg!(feature = "progress") {
#[cfg(feature = "progress")]
{
use super::progress::ProgressReader;
let data = fs::File::open(tarname)?;
let progdata = ProgressReader::new(data)?;
let decompressed = GzDecoder::new(progdata)?; let mut archive = Archive::new(decompressed); archive.unpack(&extract_path)?;
}
} else {
let data = fs::File::open(tarname)?;
let decompressed = GzDecoder::new(data)?; let mut archive = Archive::new(decompressed); archive.unpack(&extract_path)?;
};
Ok(())
}
impl<T: ?Sized> CachedBackend for T
where
T: Backend,
{
fn get_latest_supported_versions(
&self,
name: &str,
environments: Vec<String>,
) -> LalResult<Vec<u32>> {
use std::collections::BTreeSet;
let mut result = BTreeSet::new();
let mut first_pass = true;
for e in environments {
let eres: BTreeSet<_> = self.get_versions(name, &e)?.into_iter().take(100).collect();
info!("Last versions for {} in {} env is {:?}", name, e, eres);
if first_pass {
result = eres;
first_pass = false;
} else {
result = result.clone().intersection(&eres).cloned().collect();
}
}
debug!("Intersection of allowed versions {:?}", result);
Ok(result.into_iter().collect())
}
fn retrieve_published_component(
&self,
name: &str,
version: Option<u32>,
env: &str,
) -> LalResult<(PathBuf, Component)> {
trace!("Locate component {}", name);
let component = self.get_component_info(name, version, env)?;
if !is_cached(self, &component.name, component.version, env) {
let local_tarball = Path::new(".").join(format!("{}.tar", name));
self.raw_fetch(&component.location, &local_tarball)?;
store_tarball(self, name, component.version, env)?;
}
assert!(is_cached(self, &component.name, component.version, env),
"cached component");
trace!("Fetching {} from cache", name);
let tarname = get_cache_dir(self, &component.name, component.version, env)
.join(format!("{}.tar", name));
Ok((tarname, component))
}
fn unpack_published_component(
&self,
name: &str,
version: Option<u32>,
env: &str,
) -> LalResult<Component> {
let (tarname, component) = self.retrieve_published_component(name, version, env)?;
debug!("Unpacking tarball {} for {}",
tarname.to_str().unwrap(),
component.name);
extract_tarball_to_input(tarname, name)?;
Ok(component)
}
fn unpack_stashed_component(&self, name: &str, code: &str) -> LalResult<()> {
let tarpath = self.retrieve_stashed_component(name, code)?;
extract_tarball_to_input(tarpath, name)?;
Ok(())
}
fn retrieve_stashed_component(&self, name: &str, code: &str) -> LalResult<PathBuf> {
let tarpath = Path::new(&self.get_cache_dir())
.join("stash")
.join(name)
.join(code)
.join(format!("{}.tar.gz", name));
if !tarpath.is_file() {
return Err(CliError::MissingStashArtifact(format!("{}/{}", name, code)));
}
Ok(tarpath)
}
fn stash_output(&self, name: &str, code: &str) -> LalResult<()> {
let destdir = Path::new(&self.get_cache_dir()).join("stash").join(name).join(code);
debug!("Creating {:?}", destdir);
fs::create_dir_all(&destdir)?;
output::tar(&destdir.join(format!("{}.tar.gz", name)))?;
fs::copy("./OUTPUT/lockfile.json", destdir.join("lockfile.json"))?;
Ok(())
}
}