mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-11-28 22:03:30 +03:00
Merge pull request #3887 from gitbutlerapp/remove-git-tree
remove git::tree
This commit is contained in:
commit
66379af066
@ -1,4 +1,4 @@
|
||||
use super::{Commit, Oid, Result, Tree};
|
||||
use super::{Commit, Oid, Result};
|
||||
|
||||
pub struct Branch<'repo> {
|
||||
branch: git2::Branch<'repo>,
|
||||
@ -31,12 +31,8 @@ impl<'repo> Branch<'repo> {
|
||||
self.branch.get().name_bytes()
|
||||
}
|
||||
|
||||
pub fn peel_to_tree(&self) -> Result<Tree<'repo>> {
|
||||
self.branch
|
||||
.get()
|
||||
.peel_to_tree()
|
||||
.map_err(Into::into)
|
||||
.map(Into::into)
|
||||
pub fn peel_to_tree(&self) -> Result<git2::Tree<'repo>> {
|
||||
self.branch.get().peel_to_tree().map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn peel_to_commit(&self) -> Result<Commit<'repo>> {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::{Oid, Result, Signature, Tree};
|
||||
use super::{Oid, Result, Signature};
|
||||
use bstr::BStr;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -35,8 +35,8 @@ impl<'repo> Commit<'repo> {
|
||||
self.commit.parent_count()
|
||||
}
|
||||
|
||||
pub fn tree(&self) -> Result<Tree<'repo>> {
|
||||
self.commit.tree().map(Into::into).map_err(Into::into)
|
||||
pub fn tree(&self) -> Result<git2::Tree<'repo>> {
|
||||
self.commit.tree().map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn tree_id(&self) -> Oid {
|
||||
|
@ -160,8 +160,8 @@ pub fn workdir(repository: &Repository, commit_oid: &git::Oid) -> Result<DiffByP
|
||||
|
||||
pub fn trees(
|
||||
repository: &Repository,
|
||||
old_tree: &git::Tree,
|
||||
new_tree: &git::Tree,
|
||||
old_tree: &git2::Tree,
|
||||
new_tree: &git2::Tree,
|
||||
) -> Result<DiffByPathMap> {
|
||||
let mut diff_opts = git2::DiffOptions::new();
|
||||
diff_opts
|
||||
|
@ -2,30 +2,12 @@ use std::path;
|
||||
|
||||
use filetime::FileTime;
|
||||
|
||||
use super::{Error, Oid, Repository, Result, Tree};
|
||||
use super::{Oid, Repository, Result};
|
||||
|
||||
pub struct Index {
|
||||
index: git2::Index,
|
||||
}
|
||||
|
||||
impl TryFrom<Tree<'_>> for Index {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: Tree<'_>) -> std::result::Result<Self, Self::Error> {
|
||||
Self::try_from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&Tree<'_>> for Index {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: &Tree) -> Result<Self> {
|
||||
let mut empty_index = Self::new()?;
|
||||
empty_index.read_tree(value)?;
|
||||
Ok(empty_index)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a mut Index> for &'a mut git2::Index {
|
||||
fn from(index: &'a mut Index) -> Self {
|
||||
&mut index.index
|
||||
@ -62,10 +44,6 @@ impl Index {
|
||||
self.index.conflicts().map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn read_tree(&mut self, tree: &Tree) -> Result<()> {
|
||||
self.index.read_tree(tree.into()).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn write_tree_to(&mut self, repo: &Repository) -> Result<Oid> {
|
||||
self.index
|
||||
.write_tree_to(repo.into())
|
||||
|
@ -42,3 +42,6 @@ pub use self::url::*;
|
||||
|
||||
mod repository_ext;
|
||||
pub use repository_ext::*;
|
||||
|
||||
mod tree_ext;
|
||||
pub use tree_ext::*;
|
||||
|
@ -1,7 +1,7 @@
|
||||
mod refname;
|
||||
pub use refname::{LocalRefname, Refname, RemoteRefname, VirtualRefname};
|
||||
|
||||
use super::{Commit, Oid, Result, Tree};
|
||||
use super::{Commit, Oid, Result};
|
||||
|
||||
pub struct Reference<'repo> {
|
||||
reference: git2::Reference<'repo>,
|
||||
@ -35,13 +35,6 @@ impl<'repo> Reference<'repo> {
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn peel_to_tree(&self) -> Result<Tree<'repo>> {
|
||||
self.reference
|
||||
.peel_to_tree()
|
||||
.map(Into::into)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn rename(
|
||||
&mut self,
|
||||
new_name: &Refname,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::{
|
||||
Blob, Branch, Commit, Config, Index, Oid, Reference, Refname, Remote, Result, Signature, Tree,
|
||||
Blob, Branch, Commit, Config, Index, Oid, Reference, Refname, Remote, Result, Signature,
|
||||
TreeBuilder, Url,
|
||||
};
|
||||
use git2::{BlameOptions, Submodule};
|
||||
@ -98,42 +98,37 @@ impl Repository {
|
||||
|
||||
pub fn merge_trees(
|
||||
&self,
|
||||
ancestor_tree: &Tree<'_>,
|
||||
our_tree: &Tree<'_>,
|
||||
their_tree: &Tree<'_>,
|
||||
ancestor_tree: &git2::Tree<'_>,
|
||||
our_tree: &git2::Tree<'_>,
|
||||
their_tree: &git2::Tree<'_>,
|
||||
) -> Result<Index> {
|
||||
self.0
|
||||
.merge_trees(
|
||||
ancestor_tree.into(),
|
||||
our_tree.into(),
|
||||
their_tree.into(),
|
||||
None,
|
||||
)
|
||||
.merge_trees(ancestor_tree, our_tree, their_tree, None)
|
||||
.map(Index::from)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn diff_tree_to_tree(
|
||||
&self,
|
||||
old_tree: Option<&Tree<'_>>,
|
||||
new_tree: Option<&Tree<'_>>,
|
||||
old_tree: Option<&git2::Tree<'_>>,
|
||||
new_tree: Option<&git2::Tree<'_>>,
|
||||
opts: Option<&mut git2::DiffOptions>,
|
||||
) -> Result<git2::Diff<'_>> {
|
||||
self.0
|
||||
.diff_tree_to_tree(old_tree.map(Into::into), new_tree.map(Into::into), opts)
|
||||
.diff_tree_to_tree(old_tree, new_tree, opts)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn diff_tree_to_workdir(
|
||||
&self,
|
||||
old_tree: Option<&Tree<'_>>,
|
||||
old_tree: Option<&git2::Tree<'_>>,
|
||||
opts: Option<&mut git2::DiffOptions>,
|
||||
) -> Result<git2::Diff<'_>> {
|
||||
if let Ok(mut index) = self.0.index() {
|
||||
index.update_all(vec!["*"], None)?;
|
||||
}
|
||||
self.0
|
||||
.diff_tree_to_workdir_with_index(old_tree.map(Into::into), opts)
|
||||
.diff_tree_to_workdir_with_index(old_tree, opts)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
@ -160,11 +155,8 @@ impl Repository {
|
||||
self.0.head().map(Reference::from).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn find_tree(&self, id: Oid) -> Result<Tree> {
|
||||
self.0
|
||||
.find_tree(id.into())
|
||||
.map(Tree::from)
|
||||
.map_err(Into::into)
|
||||
pub fn find_tree(&self, id: Oid) -> Result<git2::Tree> {
|
||||
self.0.find_tree(id.into()).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn find_commit(&self, id: Oid) -> Result<Commit> {
|
||||
@ -238,7 +230,7 @@ impl Repository {
|
||||
author: &Signature<'_>,
|
||||
committer: &Signature<'_>,
|
||||
message: &str,
|
||||
tree: &Tree<'_>,
|
||||
tree: &git2::Tree<'_>,
|
||||
parents: &[&Commit<'_>],
|
||||
change_id: Option<&str>,
|
||||
) -> Result<Oid> {
|
||||
@ -251,7 +243,7 @@ impl Repository {
|
||||
author.into(),
|
||||
committer.into(),
|
||||
message,
|
||||
tree.into(),
|
||||
tree,
|
||||
&parents,
|
||||
)?;
|
||||
|
||||
@ -431,7 +423,7 @@ impl Repository {
|
||||
self.0.config().map(Into::into).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn treebuilder<'repo>(&'repo self, tree: Option<&'repo Tree>) -> TreeBuilder<'repo> {
|
||||
pub fn treebuilder<'repo>(&'repo self, tree: Option<&'repo git2::Tree>) -> TreeBuilder<'repo> {
|
||||
TreeBuilder::new(self, tree)
|
||||
}
|
||||
|
||||
@ -528,9 +520,9 @@ impl Repository {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn checkout_tree<'a>(&'a self, tree: &'a Tree<'a>) -> CheckoutTreeBuidler {
|
||||
pub fn checkout_tree<'a>(&'a self, tree: &'a git2::Tree<'a>) -> CheckoutTreeBuidler {
|
||||
CheckoutTreeBuidler {
|
||||
tree: tree.into(),
|
||||
tree,
|
||||
repo: &self.0,
|
||||
checkout_builder: git2::build::CheckoutBuilder::new(),
|
||||
}
|
||||
|
@ -1,93 +1,6 @@
|
||||
use std::path::Path;
|
||||
|
||||
use super::{Oid, Repository, Result};
|
||||
use crate::path::Normalize;
|
||||
|
||||
pub struct Tree<'repo> {
|
||||
pub tree: git2::Tree<'repo>,
|
||||
}
|
||||
|
||||
impl<'repo> From<git2::Tree<'repo>> for Tree<'repo> {
|
||||
fn from(tree: git2::Tree<'repo>) -> Self {
|
||||
Tree { tree }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'repo> From<&'repo Tree<'repo>> for &'repo git2::Tree<'repo> {
|
||||
fn from(tree: &'repo Tree<'repo>) -> Self {
|
||||
&tree.tree
|
||||
}
|
||||
}
|
||||
|
||||
impl<'repo> Tree<'repo> {
|
||||
pub fn id(&self) -> Oid {
|
||||
self.tree.id().into()
|
||||
}
|
||||
|
||||
pub fn get_path<P: AsRef<Path>>(&self, path: P) -> Result<TreeEntry<'repo>> {
|
||||
self.tree
|
||||
.get_path(path.normalize().as_path())
|
||||
.map(Into::into)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn walk<C>(&self, mut callback: C) -> Result<()>
|
||||
where
|
||||
C: FnMut(&str, &TreeEntry) -> TreeWalkResult,
|
||||
{
|
||||
self.tree
|
||||
.walk(git2::TreeWalkMode::PreOrder, |root, entry| {
|
||||
match callback(root, &entry.clone().into()) {
|
||||
TreeWalkResult::Continue => git2::TreeWalkResult::Ok,
|
||||
TreeWalkResult::Skip => git2::TreeWalkResult::Skip,
|
||||
TreeWalkResult::Stop => git2::TreeWalkResult::Abort,
|
||||
}
|
||||
})
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn get_name(&self, filename: &str) -> Option<TreeEntry> {
|
||||
self.tree.get_name(filename).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum TreeWalkResult {
|
||||
Continue,
|
||||
Skip,
|
||||
Stop,
|
||||
}
|
||||
|
||||
pub struct TreeEntry<'repo> {
|
||||
entry: git2::TreeEntry<'repo>,
|
||||
}
|
||||
|
||||
impl<'repo> From<git2::TreeEntry<'repo>> for TreeEntry<'repo> {
|
||||
fn from(entry: git2::TreeEntry<'repo>) -> Self {
|
||||
TreeEntry { entry }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'repo> TreeEntry<'repo> {
|
||||
pub fn filemode(&self) -> i32 {
|
||||
self.entry.filemode()
|
||||
}
|
||||
|
||||
pub fn to_object(&self, repo: &'repo Repository) -> Result<git2::Object> {
|
||||
self.entry.to_object(repo.into()).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> Option<git2::ObjectType> {
|
||||
self.entry.kind()
|
||||
}
|
||||
|
||||
pub fn id(&self) -> Oid {
|
||||
self.entry.id().into()
|
||||
}
|
||||
|
||||
pub fn name(&self) -> Option<&str> {
|
||||
self.entry.name()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum FileMode {
|
||||
@ -115,11 +28,11 @@ pub struct TreeBuilder<'repo> {
|
||||
}
|
||||
|
||||
impl<'repo> TreeBuilder<'repo> {
|
||||
pub fn new(repo: &'repo Repository, base: Option<&'repo Tree>) -> Self {
|
||||
pub fn new(repo: &'repo Repository, base: Option<&'repo git2::Tree>) -> Self {
|
||||
TreeBuilder {
|
||||
repo: repo.into(),
|
||||
builder: git2::build::TreeUpdateBuilder::new(),
|
||||
base: base.map(Into::into),
|
||||
base,
|
||||
}
|
||||
}
|
||||
|
||||
|
19
crates/gitbutler-core/src/git/tree_ext.rs
Normal file
19
crates/gitbutler-core/src/git/tree_ext.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use crate::path::Normalize;
|
||||
use anyhow::Result;
|
||||
use git2::TreeEntry;
|
||||
use std::path::Path;
|
||||
|
||||
/// Extension trait for `git2::Tree`.
|
||||
///
|
||||
/// For now, it collects useful methods from `gitbutler-core::git::Tree`
|
||||
pub trait TreeExt {
|
||||
fn get_path<P: AsRef<Path>>(&self, path: P) -> Result<TreeEntry<'_>>;
|
||||
}
|
||||
|
||||
impl<'repo> TreeExt for git2::Tree<'repo> {
|
||||
fn get_path<P: AsRef<Path>>(&self, path: P) -> Result<TreeEntry<'repo>> {
|
||||
self.get_path(path.normalize().as_path())
|
||||
.map(Into::into)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
@ -340,7 +340,7 @@ impl Repository {
|
||||
&self,
|
||||
user: Option<&users::User>,
|
||||
message: &str,
|
||||
tree: &git::Tree,
|
||||
tree: &git2::Tree,
|
||||
parents: &[&git::Commit],
|
||||
change_id: Option<&str>,
|
||||
) -> Result<git::Oid> {
|
||||
|
@ -5,10 +5,10 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use anyhow::Result;
|
||||
use serde::{ser::SerializeStruct, Serialize};
|
||||
|
||||
use crate::{git, lock, path::Normalize};
|
||||
use crate::git::{self};
|
||||
|
||||
#[derive(Debug, Clone, thiserror::Error)]
|
||||
pub enum Error {
|
||||
@ -37,216 +37,6 @@ impl From<FromError> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Reader<'reader> {
|
||||
Filesystem(FilesystemReader),
|
||||
Commit(CommitReader<'reader>),
|
||||
Prefixed(PrefixedReader<'reader>),
|
||||
}
|
||||
|
||||
impl<'reader> Reader<'reader> {
|
||||
pub fn open<P: AsRef<Path>>(root: P) -> Result<Self, io::Error> {
|
||||
FilesystemReader::open(root).map(Reader::Filesystem)
|
||||
}
|
||||
|
||||
pub fn sub<P: AsRef<Path>>(&'reader self, prefix: P) -> Self {
|
||||
Reader::Prefixed(PrefixedReader::new(self, prefix))
|
||||
}
|
||||
|
||||
pub fn commit_id(&self) -> Option<git::Oid> {
|
||||
match self {
|
||||
Reader::Filesystem(_) => None,
|
||||
Reader::Commit(reader) => Some(reader.get_commit_oid()),
|
||||
Reader::Prefixed(reader) => reader.reader.commit_id(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_commit(
|
||||
repository: &'reader git::Repository,
|
||||
commit: &git::Commit<'reader>,
|
||||
) -> Result<Self> {
|
||||
Ok(Reader::Commit(CommitReader::new(repository, commit)?))
|
||||
}
|
||||
|
||||
pub fn exists<P: AsRef<Path>>(&self, file_path: P) -> Result<bool, io::Error> {
|
||||
match self {
|
||||
Reader::Filesystem(reader) => reader.exists(file_path),
|
||||
Reader::Commit(reader) => Ok(reader.exists(file_path)),
|
||||
Reader::Prefixed(reader) => reader.exists(file_path),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read<P: AsRef<Path>>(&self, path: P) -> Result<Content, Error> {
|
||||
let mut contents = self.batch(&[path])?;
|
||||
contents
|
||||
.pop()
|
||||
.expect("batch should return at least one result")
|
||||
}
|
||||
|
||||
pub fn batch<P: AsRef<Path>>(
|
||||
&self,
|
||||
paths: &[P],
|
||||
) -> Result<Vec<Result<Content, Error>>, io::Error> {
|
||||
match self {
|
||||
Reader::Filesystem(reader) => reader.batch(|root| {
|
||||
paths
|
||||
.iter()
|
||||
.map(|path| {
|
||||
let path = root.join(path);
|
||||
if !path.exists() {
|
||||
return Err(Error::NotFound);
|
||||
}
|
||||
let content = Content::read_from_file(&path)?;
|
||||
Ok(content)
|
||||
})
|
||||
.collect()
|
||||
}),
|
||||
Reader::Commit(reader) => Ok(paths
|
||||
.iter()
|
||||
.map(|path| reader.read(path.normalize()))
|
||||
.collect()),
|
||||
Reader::Prefixed(reader) => reader.batch(paths),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list_files<P: AsRef<Path>>(&self, dir_path: P) -> Result<Vec<PathBuf>> {
|
||||
match self {
|
||||
Reader::Filesystem(reader) => reader.list_files(dir_path.as_ref()),
|
||||
Reader::Commit(reader) => reader.list_files(dir_path.as_ref()),
|
||||
Reader::Prefixed(reader) => reader.list_files(dir_path.as_ref()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FilesystemReader(lock::Dir);
|
||||
|
||||
impl FilesystemReader {
|
||||
fn open<P: AsRef<Path>>(root: P) -> Result<Self, io::Error> {
|
||||
lock::Dir::new(root).map(Self)
|
||||
}
|
||||
|
||||
fn exists<P: AsRef<Path>>(&self, path: P) -> Result<bool, io::Error> {
|
||||
let exists = self.0.batch(|root| root.join(path.as_ref()).exists())?;
|
||||
Ok(exists)
|
||||
}
|
||||
|
||||
fn batch<R>(&self, action: impl FnOnce(&Path) -> R) -> Result<R, io::Error> {
|
||||
self.0.batch(action)
|
||||
}
|
||||
|
||||
fn list_files<P: AsRef<Path>>(&self, path: P) -> Result<Vec<PathBuf>> {
|
||||
let path = path.as_ref();
|
||||
self.0
|
||||
.batch(|root| crate::fs::list_files(root.join(path).as_path(), &[Path::new(".git")]))?
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CommitReader<'reader> {
|
||||
repository: &'reader git::Repository,
|
||||
commit_oid: git::Oid,
|
||||
tree: git::Tree<'reader>,
|
||||
}
|
||||
|
||||
impl<'reader> CommitReader<'reader> {
|
||||
pub fn new(
|
||||
repository: &'reader git::Repository,
|
||||
commit: &git::Commit<'reader>,
|
||||
) -> Result<CommitReader<'reader>> {
|
||||
let tree = commit
|
||||
.tree()
|
||||
.with_context(|| format!("{}: tree not found", commit.id()))?;
|
||||
Ok(CommitReader {
|
||||
repository,
|
||||
tree,
|
||||
commit_oid: commit.id(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_commit_oid(&self) -> git::Oid {
|
||||
self.commit_oid
|
||||
}
|
||||
|
||||
fn read<P: AsRef<Path>>(&self, path: P) -> Result<Content, Error> {
|
||||
let path = path.as_ref();
|
||||
let entry = match self
|
||||
.tree
|
||||
.get_path(Path::new(path))
|
||||
.context(format!("{}: tree entry not found", path.display()))
|
||||
{
|
||||
Ok(entry) => entry,
|
||||
Err(_) => return Err(Error::NotFound),
|
||||
};
|
||||
let blob = match self.repository.find_blob(entry.id()) {
|
||||
Ok(blob) => blob,
|
||||
Err(_) => return Err(Error::NotFound),
|
||||
};
|
||||
Ok(Content::from(&blob))
|
||||
}
|
||||
|
||||
pub fn list_files<P: AsRef<Path>>(&self, dir_path: P) -> Result<Vec<PathBuf>> {
|
||||
let dir_path = dir_path.as_ref();
|
||||
let mut files = vec![];
|
||||
self.tree
|
||||
.walk(|root, entry| {
|
||||
if entry.kind() == Some(git2::ObjectType::Tree) {
|
||||
return git::TreeWalkResult::Continue;
|
||||
}
|
||||
|
||||
if entry.name().is_none() {
|
||||
return git::TreeWalkResult::Continue;
|
||||
}
|
||||
let entry_path = Path::new(root).join(entry.name().unwrap());
|
||||
|
||||
if !entry_path.starts_with(dir_path) {
|
||||
return git::TreeWalkResult::Continue;
|
||||
}
|
||||
|
||||
files.push(entry_path.strip_prefix(dir_path).unwrap().to_path_buf());
|
||||
|
||||
git::TreeWalkResult::Continue
|
||||
})
|
||||
.with_context(|| format!("{}: tree walk failed", dir_path.display()))?;
|
||||
|
||||
Ok(files)
|
||||
}
|
||||
|
||||
pub fn exists<P: AsRef<Path>>(&self, file_path: P) -> bool {
|
||||
self.tree.get_path(file_path.normalize()).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PrefixedReader<'r> {
|
||||
reader: &'r Reader<'r>,
|
||||
prefix: PathBuf,
|
||||
}
|
||||
|
||||
impl<'r> PrefixedReader<'r> {
|
||||
fn new<P: AsRef<Path>>(reader: &'r Reader, prefix: P) -> Self {
|
||||
PrefixedReader {
|
||||
reader,
|
||||
prefix: prefix.as_ref().to_path_buf(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn batch<P: AsRef<Path>>(
|
||||
&self,
|
||||
paths: &[P],
|
||||
) -> Result<Vec<Result<Content, Error>>, io::Error> {
|
||||
let paths = paths
|
||||
.iter()
|
||||
.map(|path| self.prefix.join(path))
|
||||
.collect::<Vec<_>>();
|
||||
self.reader.batch(paths.as_slice())
|
||||
}
|
||||
|
||||
fn list_files<P: AsRef<Path>>(&self, dir_path: P) -> Result<Vec<PathBuf>> {
|
||||
self.reader.list_files(self.prefix.join(dir_path.as_ref()))
|
||||
}
|
||||
|
||||
fn exists<P: AsRef<Path>>(&self, file_path: P) -> Result<bool, io::Error> {
|
||||
self.reader.exists(self.prefix.join(file_path.as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, thiserror::Error)]
|
||||
pub enum FromError {
|
||||
#[error(transparent)]
|
||||
|
@ -439,7 +439,7 @@ pub fn update_base_branch(
|
||||
let branch_merge_index_tree_oid =
|
||||
branch_tree_merge_index.write_tree_to(repo)?;
|
||||
|
||||
if branch_merge_index_tree_oid == new_target_tree.id() {
|
||||
if branch_merge_index_tree_oid == new_target_tree.id().into() {
|
||||
return result_integrated_detected(branch);
|
||||
}
|
||||
|
||||
|
@ -428,7 +428,7 @@ pub fn apply_branch(
|
||||
}
|
||||
}
|
||||
|
||||
branch.tree = repo.find_commit(branch.head)?.tree()?.id();
|
||||
branch.tree = repo.find_commit(branch.head)?.tree()?.id().into();
|
||||
vb_state.set_branch(branch.clone())?;
|
||||
}
|
||||
|
||||
@ -440,7 +440,7 @@ pub fn apply_branch(
|
||||
|
||||
// check index for conflicts
|
||||
let mut merge_index = repo
|
||||
.merge_trees(&target_tree, &wd_tree.into(), &branch_tree)
|
||||
.merge_trees(&target_tree, &wd_tree, &branch_tree)
|
||||
.context("failed to merge trees")?;
|
||||
|
||||
if merge_index.has_conflicts() {
|
||||
@ -740,7 +740,7 @@ fn find_base_tree<'a>(
|
||||
repo: &'a git::Repository,
|
||||
branch_commit: &'a git::Commit<'a>,
|
||||
target_commit: &'a git::Commit<'a>,
|
||||
) -> Result<git::Tree<'a>> {
|
||||
) -> Result<git2::Tree<'a>> {
|
||||
// find merge base between target_commit and branch_commit
|
||||
let merge_base = repo
|
||||
.merge_base(target_commit.id(), branch_commit.id())
|
||||
@ -1110,7 +1110,7 @@ pub fn create_virtual_branch(
|
||||
applied: true,
|
||||
upstream: None,
|
||||
upstream_head: None,
|
||||
tree: tree.id(),
|
||||
tree: tree.id().into(),
|
||||
head: default_target.sha,
|
||||
created_timestamp_ms: now,
|
||||
updated_timestamp_ms: now,
|
||||
@ -1269,7 +1269,7 @@ pub fn integrate_upstream_commits(
|
||||
.find_commit(get_workspace_head(&vb_state, project_repository)?)?
|
||||
.tree()?;
|
||||
|
||||
let mut merge_index = repo.merge_trees(&integration_tree, &new_head_tree, &wd_tree.into())?;
|
||||
let mut merge_index = repo.merge_trees(&integration_tree, &new_head_tree, &wd_tree)?;
|
||||
|
||||
if merge_index.has_conflicts() {
|
||||
repo.checkout_index(&mut merge_index)
|
||||
@ -1279,7 +1279,7 @@ pub fn integrate_upstream_commits(
|
||||
.checkout()?;
|
||||
} else {
|
||||
branch.head = new_head;
|
||||
branch.tree = head_commit.tree()?.id();
|
||||
branch.tree = head_commit.tree()?.id().into();
|
||||
vb_state.set_branch(branch.clone())?;
|
||||
repo.checkout_index(&mut merge_index).force().checkout()?;
|
||||
};
|
||||
@ -1313,7 +1313,7 @@ pub fn integrate_with_merge(
|
||||
let upstream_branch = branch.upstream.as_ref().context("upstream not found")?;
|
||||
let merge_tree = repo.find_commit(merge_base).and_then(|c| c.tree())?;
|
||||
|
||||
let mut merge_index = repo.merge_trees(&merge_tree, &wd_tree.into(), &remote_tree)?;
|
||||
let mut merge_index = repo.merge_trees(&merge_tree, &wd_tree, &remote_tree)?;
|
||||
|
||||
if merge_index.has_conflicts() {
|
||||
let conflicts = merge_index.conflicts()?;
|
||||
@ -2097,7 +2097,7 @@ pub fn write_tree_onto_commit(
|
||||
|
||||
pub fn write_tree_onto_tree(
|
||||
project_repository: &project_repository::Repository,
|
||||
base_tree: &git::Tree,
|
||||
base_tree: &git2::Tree,
|
||||
files: impl IntoIterator<Item = (impl Borrow<PathBuf>, impl Borrow<Vec<diff::GitHunk>>)>,
|
||||
) -> Result<git::Oid> {
|
||||
let git_repository = &project_repository.git_repository;
|
||||
@ -2178,7 +2178,7 @@ pub fn write_tree_onto_tree(
|
||||
} else {
|
||||
// blob from tree_entry
|
||||
let blob = tree_entry
|
||||
.to_object(git_repository)
|
||||
.to_object(git_repository.into())
|
||||
.unwrap()
|
||||
.peel_to_blob()
|
||||
.context("failed to get blob")?;
|
||||
@ -2538,7 +2538,7 @@ fn is_commit_integrated(
|
||||
|
||||
// if the merge_tree is the same as the new_target_tree and there are no files (uncommitted changes)
|
||||
// then the vbranch is fully merged
|
||||
Ok(merge_tree_oid == upstream_tree.id())
|
||||
Ok(merge_tree_oid == upstream_tree.id().into())
|
||||
}
|
||||
|
||||
pub fn is_remote_branch_mergeable(
|
||||
@ -2580,7 +2580,7 @@ pub fn is_remote_branch_mergeable(
|
||||
let branch_tree = branch_commit.tree().context("failed to find branch tree")?;
|
||||
let mergeable = !project_repository
|
||||
.git_repository
|
||||
.merge_trees(&base_tree, &branch_tree, &wd_tree.into())
|
||||
.merge_trees(&base_tree, &branch_tree, &wd_tree)
|
||||
.context("failed to merge trees")?
|
||||
.has_conflicts();
|
||||
|
||||
@ -2644,7 +2644,7 @@ pub fn is_virtual_branch_mergeable(
|
||||
|
||||
let is_mergeable = !project_repository
|
||||
.git_repository
|
||||
.merge_trees(&base_tree, &branch_tree, &wd_tree.into())
|
||||
.merge_trees(&base_tree, &branch_tree, &wd_tree)
|
||||
.context("failed to merge trees")?
|
||||
.has_conflicts();
|
||||
|
||||
@ -4133,7 +4133,7 @@ pub fn create_virtual_branch_from_branch(
|
||||
applied: false,
|
||||
upstream_head: upstream_branch.is_some().then_some(head_commit.id()),
|
||||
upstream: upstream_branch,
|
||||
tree: head_commit_tree.id(),
|
||||
tree: head_commit_tree.id().into(),
|
||||
head: head_commit.id(),
|
||||
created_timestamp_ms: now,
|
||||
updated_timestamp_ms: now,
|
||||
|
@ -8,7 +8,6 @@ mod git;
|
||||
mod keys;
|
||||
mod lock;
|
||||
mod ops;
|
||||
mod reader;
|
||||
mod types;
|
||||
pub mod virtual_branches;
|
||||
mod zip;
|
||||
|
@ -1,183 +0,0 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use anyhow::Result;
|
||||
use gitbutler_core::reader::{CommitReader, Content, Reader};
|
||||
|
||||
use gitbutler_testsupport::{commit_all, temp_dir, test_repository};
|
||||
|
||||
#[test]
|
||||
fn directory_reader_read_file() -> Result<()> {
|
||||
let dir = temp_dir();
|
||||
|
||||
let file_path = Path::new("test.txt");
|
||||
fs::write(dir.path().join(file_path), "test")?;
|
||||
|
||||
let reader = Reader::open(dir.path())?;
|
||||
assert_eq!(reader.read(file_path)?, Content::UTF8("test".to_string()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn commit_reader_read_file() -> Result<()> {
|
||||
let (repository, _tmp) = test_repository();
|
||||
|
||||
let file_path = Path::new("test.txt");
|
||||
fs::write(repository.path().parent().unwrap().join(file_path), "test")?;
|
||||
|
||||
let oid = commit_all(&repository);
|
||||
|
||||
fs::write(repository.path().parent().unwrap().join(file_path), "test2")?;
|
||||
|
||||
let reader = Reader::from_commit(&repository, &repository.find_commit(oid)?)?;
|
||||
assert_eq!(reader.read(file_path)?, Content::UTF8("test".to_string()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reader_list_files_should_return_relative() -> Result<()> {
|
||||
let dir = temp_dir();
|
||||
|
||||
fs::write(dir.path().join("test1.txt"), "test")?;
|
||||
fs::create_dir_all(dir.path().join("dir"))?;
|
||||
fs::write(dir.path().join("dir").join("test.txt"), "test")?;
|
||||
|
||||
let reader = Reader::open(dir.path())?;
|
||||
let files = reader.list_files(Path::new("dir"))?;
|
||||
assert_eq!(files.len(), 1);
|
||||
assert!(files.contains(&Path::new("test.txt").to_path_buf()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reader_list_files() -> Result<()> {
|
||||
let dir = temp_dir();
|
||||
|
||||
fs::write(dir.path().join("test.txt"), "test")?;
|
||||
fs::create_dir_all(dir.path().join("dir"))?;
|
||||
fs::write(dir.path().join("dir").join("test.txt"), "test")?;
|
||||
|
||||
let reader = Reader::open(dir.path())?;
|
||||
let files = reader.list_files(Path::new(""))?;
|
||||
assert_eq!(files.len(), 2);
|
||||
assert!(files.contains(&Path::new("test.txt").to_path_buf()));
|
||||
assert!(files.contains(&Path::new("dir/test.txt").to_path_buf()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn commit_reader_list_files_should_return_relative() -> Result<()> {
|
||||
let (repository, _tmp) = test_repository();
|
||||
|
||||
fs::write(
|
||||
repository.path().parent().unwrap().join("test1.txt"),
|
||||
"test",
|
||||
)?;
|
||||
fs::create_dir_all(repository.path().parent().unwrap().join("dir"))?;
|
||||
fs::write(
|
||||
repository
|
||||
.path()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.join("dir")
|
||||
.join("test.txt"),
|
||||
"test",
|
||||
)?;
|
||||
|
||||
let oid = commit_all(&repository);
|
||||
|
||||
fs::remove_dir_all(repository.path().parent().unwrap().join("dir"))?;
|
||||
|
||||
let reader = CommitReader::new(&repository, &repository.find_commit(oid)?)?;
|
||||
let files = reader.list_files(Path::new("dir"))?;
|
||||
assert_eq!(files.len(), 1);
|
||||
assert!(files.contains(&Path::new("test.txt").to_path_buf()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn commit_reader_list_files() -> Result<()> {
|
||||
let (repository, _tmp) = test_repository();
|
||||
|
||||
fs::write(repository.path().parent().unwrap().join("test.txt"), "test")?;
|
||||
fs::create_dir_all(repository.path().parent().unwrap().join("dir"))?;
|
||||
fs::write(
|
||||
repository
|
||||
.path()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.join("dir")
|
||||
.join("test.txt"),
|
||||
"test",
|
||||
)?;
|
||||
|
||||
let oid = commit_all(&repository);
|
||||
|
||||
fs::remove_dir_all(repository.path().parent().unwrap().join("dir"))?;
|
||||
|
||||
let reader = CommitReader::new(&repository, &repository.find_commit(oid)?)?;
|
||||
let files = reader.list_files(Path::new(""))?;
|
||||
assert_eq!(files.len(), 2);
|
||||
assert!(files.contains(&Path::new("test.txt").to_path_buf()));
|
||||
assert!(files.contains(&Path::new("dir/test.txt").to_path_buf()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn directory_reader_exists() -> Result<()> {
|
||||
let dir = temp_dir();
|
||||
|
||||
fs::write(dir.path().join("test.txt"), "test")?;
|
||||
|
||||
let reader = Reader::open(dir.path())?;
|
||||
assert!(reader.exists(Path::new("test.txt"))?);
|
||||
assert!(!reader.exists(Path::new("test2.txt"))?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn commit_reader_exists() -> Result<()> {
|
||||
let (repository, _tmp) = test_repository();
|
||||
|
||||
fs::write(repository.path().parent().unwrap().join("test.txt"), "test")?;
|
||||
|
||||
let oid = commit_all(&repository);
|
||||
|
||||
fs::remove_file(repository.path().parent().unwrap().join("test.txt"))?;
|
||||
|
||||
let reader = CommitReader::new(&repository, &repository.find_commit(oid)?)?;
|
||||
assert!(reader.exists(Path::new("test.txt")));
|
||||
assert!(!reader.exists(Path::new("test2.txt")));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_bytes() {
|
||||
for (bytes, expected) in [
|
||||
("test".as_bytes(), Content::UTF8("test".to_string())),
|
||||
(&[0, 159, 146, 150, 159, 146, 150], Content::Binary),
|
||||
] {
|
||||
assert_eq!(Content::from(bytes), expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_content() {
|
||||
for (content, expected) in [
|
||||
(
|
||||
Content::UTF8("test".to_string()),
|
||||
r#"{"type":"utf8","value":"test"}"#,
|
||||
),
|
||||
(Content::Binary, r#"{"type":"binary"}"#),
|
||||
(Content::Large, r#"{"type":"large"}"#),
|
||||
] {
|
||||
assert_eq!(serde_json::to_string(&content).unwrap(), expected);
|
||||
}
|
||||
}
|
@ -13,8 +13,9 @@ use std::{
|
||||
};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use git2::TreeEntry;
|
||||
use gitbutler_core::{
|
||||
git,
|
||||
git::{self},
|
||||
virtual_branches::{
|
||||
self, apply_branch,
|
||||
branch::{BranchCreateRequest, BranchOwnershipClaims},
|
||||
@ -1991,16 +1992,16 @@ fn commit_executable_and_symlinks() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tree_to_file_list(repository: &git::Repository, tree: &git::Tree) -> Vec<String> {
|
||||
fn tree_to_file_list(repository: &git::Repository, tree: &git2::Tree) -> Vec<String> {
|
||||
let mut file_list = Vec::new();
|
||||
tree.walk(|_, entry| {
|
||||
walk(tree, |_, entry| {
|
||||
let path = entry.name().unwrap();
|
||||
let entry = tree.get_path(Path::new(path)).unwrap();
|
||||
let object = entry.to_object(repository).unwrap();
|
||||
let object = entry.to_object(repository.into()).unwrap();
|
||||
if object.kind() == Some(git2::ObjectType::Blob) {
|
||||
file_list.push(path.to_string());
|
||||
}
|
||||
git::TreeWalkResult::Continue
|
||||
TreeWalkResult::Continue
|
||||
})
|
||||
.expect("failed to walk tree");
|
||||
file_list
|
||||
@ -2008,13 +2009,13 @@ fn tree_to_file_list(repository: &git::Repository, tree: &git::Tree) -> Vec<Stri
|
||||
|
||||
fn tree_to_entry_list(
|
||||
repository: &git::Repository,
|
||||
tree: &git::Tree,
|
||||
tree: &git2::Tree,
|
||||
) -> Vec<(String, String, String, String)> {
|
||||
let mut file_list = Vec::new();
|
||||
tree.walk(|_root, entry| {
|
||||
walk(tree, |_root, entry| {
|
||||
let path = entry.name().unwrap();
|
||||
let entry = tree.get_path(Path::new(path)).unwrap();
|
||||
let object = entry.to_object(repository).unwrap();
|
||||
let object = entry.to_object(repository.into()).unwrap();
|
||||
let blob = object.as_blob().expect("failed to get blob");
|
||||
// convert content to string
|
||||
let octal_mode = format!("{:o}", entry.filemode());
|
||||
@ -2035,7 +2036,7 @@ fn tree_to_entry_list(
|
||||
blob.id().to_string(),
|
||||
));
|
||||
}
|
||||
git::TreeWalkResult::Continue
|
||||
TreeWalkResult::Continue
|
||||
})
|
||||
.expect("failed to walk tree");
|
||||
file_list
|
||||
@ -2267,3 +2268,23 @@ fn commit_msg_hook_rejection() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn walk<C>(tree: &git2::Tree, mut callback: C) -> Result<()>
|
||||
where
|
||||
C: FnMut(&str, &TreeEntry) -> TreeWalkResult,
|
||||
{
|
||||
tree.walk(git2::TreeWalkMode::PreOrder, |root, entry| {
|
||||
match callback(root, &entry.clone()) {
|
||||
TreeWalkResult::Continue => git2::TreeWalkResult::Ok,
|
||||
// TreeWalkResult::Skip => git2::TreeWalkResult::Skip,
|
||||
// TreeWalkResult::Stop => git2::TreeWalkResult::Abort,
|
||||
}
|
||||
})
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
enum TreeWalkResult {
|
||||
Continue,
|
||||
// Skip,
|
||||
// Stop,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user