use crate::imports::*;
use crate::utils::*;
use crate::html::*;
type E = anyhow::Error;
pub trait Component : Debug {
fn default_desc(&self) -> Html;
#[throws(E)]
fn bundle(&self, outbasepath : &String) -> Option<String>;
}
#[derive(Debug)]
pub struct FileComponent(pub String);
impl Component for FileComponent {
fn default_desc(&self) -> Html {
Html(format!(r#"file {}"#, Html::from_literal(&self.0).0))
}
#[throws(E)]
fn bundle(&self, outbasepath : &String) -> Option<String> {
let src = &self.0;
fs::copy(src, outbasepath)?;
None
}
}
#[derive(Debug)]
pub struct DirectoryComponent(Box<dyn Component>);
impl DirectoryComponent {
#[throws(E)]
pub fn new(src : String) -> DirectoryComponent {
let is_git = match fs::metadata(src.to_owned() + "/.git") {
Ok(_) => true,
Err(e) if e.kind() == NotFound => false,
Err(e) => throw!(e),
};
DirectoryComponent(if is_git {
Box::new( GitComponent(src) )
} else {
Box::new( RawDirectoryComponent(src) )
})
}
}
impl Component for DirectoryComponent {
fn default_desc(&self) -> Html { self.0.default_desc() }
#[throws(E)]
fn bundle(&self, outbasepath : &String) -> Option<String> {
self.0.bundle(outbasepath)?
}
}
#[derive(Debug)]
pub struct RawDirectoryComponent(pub String);
impl Component for RawDirectoryComponent {
fn default_desc(&self) -> Html {
Html(format!(r#"directory {}"#, Html::from_literal(&self.0).0))
}
#[throws(E)]
fn bundle(&self, outbasepath : &String) -> Option<String> {
let src = &self.0;
let mut split = src.rsplitn(2,'/');
let srcleaf = split.next().unwrap();
let dir = split.next().ok_or_else(||
anyhow!("trying to bundle directory with no parent in pathname"))?;
let outfile = outbasepath.to_owned() + ".tar";
let stdout = File::create(&outfile)?;
let mut cmd = tar_command();
cmd
.current_dir(&dir)
.stdout(stdout)
.args(&["-cf","-","--",srcleaf]);
run_cmd(cmd).cxm(||format!("tar for raw directory {:?}", &dir))?;
Some(".tar".to_owned())
}
}
#[derive(Debug)]
pub struct GitComponent(pub String);
impl Component for GitComponent {
fn default_desc(&self) -> Html {
Html(format!(r#"git working directory {}"#,
Html::from_literal(&self.0).0))
}
#[throws(E)]
fn bundle(&self, outbasepath : &String) -> Option<String> {
let src = &self.0;
let gitclone = r#"#!/bin/bash
set -e
set -o pipefail
src="$1"; shift
dest="$1"; shift
rm -rf "$dest"
mkdir "$dest"
cd "$dest"
desta=$(pwd)
git init -q
git fetch -q "$src" HEAD
git update-ref refs/heads/master FETCH_HEAD
(
set -e
cd "$src"
git ls-files --exclude-standard -oc -z
) | (
cd "$src"
cpio -p0 -dum --no-preserve-owner --quiet "$desta"
)
git reset -q
cd ..
"#;
let mut c = Command::new("bash");
c.args(&["-ec",gitclone,"x",&src,outbasepath]);
run_cmd(c).context("git fetch, copy etc. script")?;
let r = RawDirectoryComponent(outbasepath.clone()).bundle(outbasepath)?;
remove_dir_all(outbasepath)?;
r
}
}