use itertools::Itertools;
use std::error::Error;
use std::path::{Path, PathBuf};
use std::str;
use std::str::FromStr;
use crate::model::{TxnData, Txns};
use crate::parser::tackler_parser;
use gix as git;
use gix::objs::tree::EntryKind;
use crate::kernel::Settings;
use tackler_api::metadata::items::{GitInputReference, MetadataItem};
pub enum GitInputSelector {
CommitId(String),
Reference(String),
}
pub fn string_to_txns(input: &str, settings: &mut Settings) -> Result<TxnData, Box<dyn Error>> {
let txns = tackler_parser::txns_text(input, settings)?;
TxnData::from(None, txns, &settings.get_hash())
}
pub fn paths_to_txns(
paths: &[PathBuf],
settings: &mut Settings,
) -> Result<TxnData, Box<dyn Error>> {
let txns: Result<Txns, Box<dyn Error>> = paths
.iter()
.map(|p| tackler_parser::txns_file(p, settings))
.flatten_ok()
.collect();
TxnData::from(None, txns?, &settings.get_hash())
}
pub fn git_to_txns(
repo_path: &Path,
dir: &str,
extension: &str,
input_selector: GitInputSelector,
settings: &mut Settings,
) -> Result<TxnData, Box<dyn Error>> {
let repo = git::discover(repo_path)?;
let (object, reference) = match input_selector {
GitInputSelector::CommitId(id) => {
let object_id = gix::ObjectId::from_str(&id)?;
(repo.find_object(object_id)?.try_into_commit()?, None)
}
GitInputSelector::Reference(ref_str) => {
let git_ref = repo.find_reference(&ref_str)?;
let id = git_ref.into_fully_peeled_id()?;
(
repo.find_object(id)?.try_into_commit()?,
Some(ref_str.clone()),
)
}
};
let gitmd = GitInputReference {
commit: object.id.to_string(),
reference,
dir: dir.to_string(),
suffix: extension.to_string(),
message: object.message()?.title.to_string(),
};
let tree = object.tree()?;
let txns: Result<Txns, Box<dyn Error>> = tree
.traverse()
.breadthfirst
.files()?
.iter()
.map(|entry| {
use git::objs::tree::EntryKind::Blob;
match EntryKind::from(entry.mode) {
Blob => {
if entry.filepath.starts_with(str::as_bytes(dir))
&& entry.filepath.ends_with(str::as_bytes(extension))
{
let obj = repo.find_object(entry.oid)?;
let par_res =
tackler_parser::txns_text(str::from_utf8(&obj.data)?, settings);
match par_res {
Ok(txns) => Ok(txns),
Err(err) => {
let msg = format!(
"\
GIT: Error while processing git object\n\
\x20 commit id: {}\n\
\x20 object id: {}\n\
\x20 path: {}\n\
\x20 msg: {}\
",
object.id, obj.id, entry.filepath, err
);
Err(msg.into())
}
}
} else {
Ok(Vec::default())
}
}
_ => Ok(Vec::default()),
}
})
.flatten_ok()
.collect::<Result<Txns, Box<dyn Error>>>();
TxnData::from(
Some(MetadataItem::GitInputReference(gitmd)),
txns?,
&settings.get_hash(),
)
}
#[cfg(test)]
mod tests {
}