parent
fcc89b1b5b
commit
c8f3364c74
@ -1,33 +1,38 @@ |
|||||||
//! A test binary to use during development
|
//! A test binary to use during development
|
||||||
|
|
||||||
use std::sync::mpsc::channel; |
// use std::sync::mpsc::channel;
|
||||||
use supergit::{BranchCommit, Repository}; |
// use supergit::{BranchCommit, Repository};
|
||||||
|
|
||||||
fn main() { |
// fn main() {
|
||||||
let path = match std::env::args().nth(1) { |
// let path = match std::env::args().nth(1) {
|
||||||
Some(p) => p, |
// Some(p) => p,
|
||||||
None => { |
// None => {
|
||||||
eprintln!("USAGE: supergit-test <path>"); |
// eprintln!("USAGE: supergit-test <path>");
|
||||||
std::process::exit(2); |
// std::process::exit(2);
|
||||||
} |
// }
|
||||||
}; |
// };
|
||||||
|
|
||||||
|
// let repo = Repository::open(path.as_str()).unwrap();
|
||||||
|
// let branches = repo.branches().unwrap();
|
||||||
|
// let main = branches
|
||||||
|
// .into_iter()
|
||||||
|
// .filter(|b| b.name() == Some("master".to_string()))
|
||||||
|
// .nth(0)
|
||||||
|
// .unwrap();
|
||||||
|
|
||||||
let repo = Repository::open(path.as_str()).unwrap(); |
// let head = main.get_head();
|
||||||
let branches = repo.branches().unwrap(); |
// let tree = head.get_tree();
|
||||||
let main = branches |
|
||||||
.into_iter() |
// println!(
|
||||||
.filter(|b| b.name() == Some("master".to_string())) |
// "{:#?}",
|
||||||
.nth(0) |
// tree.history(main.get_all(), "Cargo.toml")
|
||||||
.unwrap(); |
// .into_iter()
|
||||||
|
// .map(|c| c.summary())
|
||||||
|
// .collect::<Vec<_>>()
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
let head = main.get_head(); |
|
||||||
let tree = head.get_tree(); |
fn main() { |
||||||
|
|
||||||
println!( |
|
||||||
"{:#?}", |
|
||||||
tree.history(main.get_all(), "Cargo.toml") |
|
||||||
.into_iter() |
|
||||||
.map(|c| c.summary()) |
|
||||||
.collect::<Vec<_>>() |
|
||||||
); |
|
||||||
} |
} |
||||||
|
@ -0,0 +1,9 @@ |
|||||||
|
|
||||||
|
///
|
||||||
|
pub struct Explorer {} |
||||||
|
|
||||||
|
///
|
||||||
|
pub struct Yield {} |
||||||
|
|
||||||
|
///
|
||||||
|
pub enum YieldType {} |
@ -0,0 +1,15 @@ |
|||||||
|
//! File tree abstractions
|
||||||
|
//!
|
||||||
|
//! The supergit files API is split into two parts: `FileTree`, which
|
||||||
|
//! is mostly used internally and only exposed to allow external tools
|
||||||
|
//! to rely on the same indexing mechanism as supergit, and
|
||||||
|
//! `Explorer`, which is a high-level API for loading trees for
|
||||||
|
//! specific commits.
|
||||||
|
//!
|
||||||
|
|
||||||
|
pub(self) mod tree_utils; |
||||||
|
mod tree; |
||||||
|
pub use tree::{FileTree, TreeEntry, EntryType}; |
||||||
|
|
||||||
|
mod explorer; |
||||||
|
pub use explorer::{Explorer, Yield, YieldType}; |
@ -0,0 +1,104 @@ |
|||||||
|
//! Low-level abstraction over finding refs inside a commit tree
|
||||||
|
|
||||||
|
use super::tree_utils as utils; |
||||||
|
use crate::HashId; |
||||||
|
use git2::{ObjectType, Repository, TreeWalkMode, TreeWalkResult}; |
||||||
|
use std::sync::Arc; |
||||||
|
|
||||||
|
/// A git directory tree walker abstraction
|
||||||
|
///
|
||||||
|
/// This type is meant to be used ephemerally, and internally uses the
|
||||||
|
/// libgit2 `Tree` abstraction to walk directory trees lazily to
|
||||||
|
/// resolve paths to [`TreeEntry`](self::TreeEntry)'s.
|
||||||
|
///
|
||||||
|
/// Note: this type _may_ be removed in the future. For a more
|
||||||
|
/// high-level (and stable) API, check
|
||||||
|
/// [`Explorer`](crate::files::Explorer)
|
||||||
|
pub struct FileTree { |
||||||
|
repo: Arc<Repository>, |
||||||
|
c: HashId, |
||||||
|
} |
||||||
|
|
||||||
|
impl FileTree { |
||||||
|
/// Construct a new FileTree with a repository
|
||||||
|
pub(crate) fn new(repo: Arc<Repository>, c: HashId) -> Self { |
||||||
|
Self { repo, c } |
||||||
|
} |
||||||
|
|
||||||
|
/// Resolve a path inside this file tree
|
||||||
|
///
|
||||||
|
/// Will return `None` if there is no tree for the selected
|
||||||
|
/// commit, or the file inside the tree does not exist.
|
||||||
|
pub fn resolve(&self, path: &str) -> Option<TreeEntry> { |
||||||
|
let tree = utils::open_tree(&self.repo, &self.c)?; |
||||||
|
let target = utils::path_split(path); |
||||||
|
|
||||||
|
// Initialise entry to None as a fallback
|
||||||
|
let mut entry = None; |
||||||
|
|
||||||
|
// Walk over tree and swallor errors (which we use to
|
||||||
|
// terminace traversal to speed up indexing time)
|
||||||
|
let _ = tree.walk(TreeWalkMode::PreOrder, |p, e| { |
||||||
|
if utils::path_cmp(&target, p, e.name().unwrap()) { |
||||||
|
entry = Some(TreeEntry::new(p, &e)); |
||||||
|
TreeWalkResult::Ok |
||||||
|
} else { |
||||||
|
TreeWalkResult::Skip |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
// Return whatever the entry is now
|
||||||
|
entry |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// An entry in a commit tree
|
||||||
|
///
|
||||||
|
/// This type is lazily loaded, and can represent either a Blob or a
|
||||||
|
/// Directory. You can resolve its value by calling
|
||||||
|
/// [`resolve()`](Self::resolve)
|
||||||
|
pub struct TreeEntry { |
||||||
|
tt: EntryType, |
||||||
|
id: HashId, |
||||||
|
path: String, |
||||||
|
} |
||||||
|
|
||||||
|
impl TreeEntry { |
||||||
|
fn new(path: &str, entry: &git2::TreeEntry) -> Self { |
||||||
|
let tt = match entry.kind() { |
||||||
|
Some(ObjectType::Blob) => EntryType::File, |
||||||
|
Some(ObjectType::Tree) => EntryType::Dir, |
||||||
|
_ => unimplemented!(), |
||||||
|
}; |
||||||
|
let id = entry.id().into(); |
||||||
|
let path = path.into(); |
||||||
|
|
||||||
|
Self { tt, id, path } |
||||||
|
} |
||||||
|
|
||||||
|
/// Resolve this type to a [`Yield`]()
|
||||||
|
pub fn resolve(&self) {} |
||||||
|
} |
||||||
|
|
||||||
|
/// Type of a TreeEntry
|
||||||
|
pub enum EntryType { |
||||||
|
/// A file that can be loaded
|
||||||
|
File, |
||||||
|
/// A directory that can be indexed
|
||||||
|
Dir, |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn index_tree() { |
||||||
|
let path = env!("CARGO_MANIFEST_DIR").to_owned() + "/test-repo"; |
||||||
|
use crate::Repository as Repo; |
||||||
|
|
||||||
|
eprintln!("Path: `{}`", path); |
||||||
|
|
||||||
|
let r = Repo::open(&path).unwrap(); |
||||||
|
let b = r.branch("master".into()).unwrap(); |
||||||
|
let h = b.head(); |
||||||
|
|
||||||
|
let t = h.tree(); |
||||||
|
t.resolve("README".into()).unwrap(); |
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
//! A set of tree utilities used internally in the tree.rs module
|
||||||
|
|
||||||
|
use crate::HashId; |
||||||
|
use git2::{Repository, Tree}; |
||||||
|
use std::{path::PathBuf, sync::Arc}; |
||||||
|
|
||||||
|
/// Take a vector of path segments, and turn it into a valid offset path
|
||||||
|
///
|
||||||
|
/// There are tests to make sure this function works properly.
|
||||||
|
/// Following are some example transformations.
|
||||||
|
///
|
||||||
|
/// * vec![] -> ""
|
||||||
|
/// * vec!["foo"] -> "foo"
|
||||||
|
/// * vec!["foo", "bar", "baz"] -> "foo/bar/baz"
|
||||||
|
pub(super) fn path_segs_join(segments: Vec<&str>) -> String { |
||||||
|
segments |
||||||
|
.into_iter() |
||||||
|
.fold(PathBuf::new(), |buf, seg| buf.join(seg)) |
||||||
|
.as_path() |
||||||
|
.to_str() |
||||||
|
.unwrap() |
||||||
|
.to_owned() |
||||||
|
} |
||||||
|
|
||||||
|
/// Take an offset path inside the repository and split it into a vec
|
||||||
|
pub(super) fn path_split(path: &str) -> Vec<&str> { |
||||||
|
path.split("/").filter(|s| s != &"").collect() |
||||||
|
} |
||||||
|
|
||||||
|
/// Compare a path and entry to a target buffer
|
||||||
|
pub(super) fn path_cmp(target: &Vec<&str>, path: &str, entry: &str) -> bool { |
||||||
|
let mut buf = path_split(path); |
||||||
|
buf.push(entry); |
||||||
|
|
||||||
|
eprintln!("{:?}", buf); |
||||||
|
|
||||||
|
target == &buf |
||||||
|
} |
||||||
|
|
||||||
|
/// Open a tree for a particular commit
|
||||||
|
pub(super) fn open_tree<'r>(repo: &'r Arc<Repository>, c: &HashId) -> Option<Tree<'r>> { |
||||||
|
repo.find_commit(c.to_oid()).unwrap().tree().ok() |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn empty_path() { |
||||||
|
assert_eq!(path_segs_join(vec![]), String::from("")); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn one_path() { |
||||||
|
assert_eq!(path_segs_join(vec!["foo".into()]), String::from("foo")); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn nested_path() { |
||||||
|
assert_eq!( |
||||||
|
path_segs_join(vec!["foo".into(), "bar".into(), "baz".into()]), |
||||||
|
String::from("foo/bar/baz") |
||||||
|
); |
||||||
|
} |
Loading…
Reference in new issue