mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-01 20:45:57 +03:00
Merge pull request #1125 from gitbutlerapp/Virtual-branch-1
all purpose tree builder
This commit is contained in:
commit
15bdff860c
@ -433,48 +433,37 @@ impl Repository {
|
||||
// update last timestamp
|
||||
sessions::Writer::new(self).write(session)?;
|
||||
|
||||
let mut tree_builder = self
|
||||
.git_repository
|
||||
.treebuilder(None)
|
||||
.context("failed to create tree builder")?;
|
||||
tree_builder
|
||||
.insert(
|
||||
"session",
|
||||
build_session_tree(self)
|
||||
.context("failed to build session tree")?
|
||||
.into(),
|
||||
0o040000,
|
||||
)
|
||||
.context("failed to insert session tree")?;
|
||||
tree_builder
|
||||
.insert(
|
||||
"wd",
|
||||
build_wd_tree(self, project_repository)
|
||||
.context("failed to build working directory tree")?
|
||||
.into(),
|
||||
0o040000,
|
||||
)
|
||||
.context("failed to insert wd tree")?;
|
||||
tree_builder
|
||||
.insert(
|
||||
"logs",
|
||||
build_log_tree(self, project_repository)
|
||||
.context("failed to build logs tree")?
|
||||
.into(),
|
||||
0o040000,
|
||||
)
|
||||
.context("failed to insert logs tree")?;
|
||||
tree_builder
|
||||
.insert(
|
||||
"branches",
|
||||
build_branches_tree(self)
|
||||
.context("failed to build branches tree")?
|
||||
.into(),
|
||||
0o040000,
|
||||
)
|
||||
.context("failed to insert branches tree")?;
|
||||
let mut tree_builder = self.git_repository.treebuilder(None);
|
||||
tree_builder.upsert(
|
||||
"session",
|
||||
build_session_tree(self)
|
||||
.context("failed to build session tree")?
|
||||
.into(),
|
||||
git::FileMode::Tree,
|
||||
);
|
||||
tree_builder.upsert(
|
||||
"wd",
|
||||
build_wd_tree(self, project_repository)
|
||||
.context("failed to build working directory tree")?
|
||||
.into(),
|
||||
git::FileMode::Tree,
|
||||
);
|
||||
tree_builder.upsert(
|
||||
"logs",
|
||||
build_log_tree(self, project_repository)
|
||||
.context("failed to build logs tree")?
|
||||
.into(),
|
||||
git::FileMode::Tree,
|
||||
);
|
||||
tree_builder.upsert(
|
||||
"branches",
|
||||
build_branches_tree(self)
|
||||
.context("failed to build branches tree")?
|
||||
.into(),
|
||||
git::FileMode::Tree,
|
||||
);
|
||||
|
||||
let tree_id = tree_builder.write().context("failed to write tree")?.into();
|
||||
let tree_id = tree_builder.write().context("failed to write tree")?;
|
||||
|
||||
let user = self.users_store.get().context("failed to get user")?;
|
||||
|
||||
@ -613,14 +602,6 @@ impl Repository {
|
||||
let id = id?;
|
||||
let commit = repo.find_commit(id.into())?;
|
||||
|
||||
let copy_tree = |tree: &git::Tree| -> Result<git::Oid> {
|
||||
let tree_builder = self.git_repository.treebuilder(Some(tree))?;
|
||||
let tree_oid = tree_builder.write()?;
|
||||
Ok(tree_oid.into())
|
||||
};
|
||||
|
||||
let tree = self.git_repository.find_tree(copy_tree(&commit.tree()?)?)?;
|
||||
|
||||
match self.git_repository.head() {
|
||||
Result::Ok(head) => {
|
||||
let parent = head.peel_to_commit()?;
|
||||
@ -630,7 +611,7 @@ impl Repository {
|
||||
&commit.author(),
|
||||
&commit.committer(),
|
||||
commit.message().unwrap(),
|
||||
&tree,
|
||||
&commit.tree()?,
|
||||
&[&parent],
|
||||
)
|
||||
.context("failed to commit")?;
|
||||
@ -642,7 +623,7 @@ impl Repository {
|
||||
&commit.author(),
|
||||
&commit.committer(),
|
||||
commit.message().unwrap(),
|
||||
&tree,
|
||||
&commit.tree()?,
|
||||
&[],
|
||||
)
|
||||
.context("failed to commit")?;
|
||||
|
@ -1,6 +1,8 @@
|
||||
use std::path;
|
||||
|
||||
use super::{AnnotatedCommit, Branch, Commit, Index, Oid, Reference, Remote, Result, Tree};
|
||||
use super::{
|
||||
AnnotatedCommit, Branch, Commit, Index, Oid, Reference, Remote, Result, Tree, TreeBuilder,
|
||||
};
|
||||
|
||||
// wrapper around git2::Repository to get control over how it's used.
|
||||
pub struct Repository(git2::Repository);
|
||||
@ -186,8 +188,8 @@ impl Repository {
|
||||
self.0.config()
|
||||
}
|
||||
|
||||
pub fn treebuilder(&self, tree: Option<&Tree>) -> Result<git2::TreeBuilder> {
|
||||
self.0.treebuilder(tree.map(Into::into))
|
||||
pub fn treebuilder<'repo>(&'repo self, tree: Option<&'repo Tree>) -> TreeBuilder<'repo> {
|
||||
TreeBuilder::new(self, tree)
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &path::Path {
|
||||
|
@ -72,3 +72,60 @@ impl<'repo> TreeEntry<'repo> {
|
||||
self.entry.name()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum FileMode {
|
||||
Blob,
|
||||
BlobExecutable,
|
||||
Link,
|
||||
Tree,
|
||||
}
|
||||
|
||||
impl From<FileMode> for git2::FileMode {
|
||||
fn from(filemod: FileMode) -> Self {
|
||||
match filemod {
|
||||
FileMode::Blob => git2::FileMode::Blob,
|
||||
FileMode::BlobExecutable => git2::FileMode::BlobExecutable,
|
||||
FileMode::Link => git2::FileMode::Link,
|
||||
FileMode::Tree => git2::FileMode::Tree,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TreeBuilder<'repo> {
|
||||
repo: &'repo git2::Repository,
|
||||
builder: git2::build::TreeUpdateBuilder,
|
||||
base: Option<&'repo git2::Tree<'repo>>,
|
||||
}
|
||||
|
||||
impl<'repo> TreeBuilder<'repo> {
|
||||
pub fn new(repo: &'repo Repository, base: Option<&'repo Tree>) -> Self {
|
||||
TreeBuilder {
|
||||
repo: repo.into(),
|
||||
builder: git2::build::TreeUpdateBuilder::new(),
|
||||
base: base.map(Into::into),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn upsert<P: AsRef<path::Path>>(&mut self, filename: P, oid: Oid, filemode: FileMode) {
|
||||
self.builder
|
||||
.upsert(filename.as_ref(), oid.into(), filemode.into());
|
||||
}
|
||||
|
||||
pub fn remove<P: AsRef<path::Path>>(&mut self, filename: P) {
|
||||
self.builder.remove(filename.as_ref());
|
||||
}
|
||||
|
||||
pub fn write(&mut self) -> Result<Oid> {
|
||||
let repo: &git2::Repository = self.repo.into();
|
||||
if let Some(base) = self.base {
|
||||
let tree_id = self.builder.create_updated(&repo, base.into())?;
|
||||
Ok(tree_id.into())
|
||||
} else {
|
||||
let empty_tree_id = repo.treebuilder(None)?.write()?;
|
||||
let empty_tree = repo.find_tree(empty_tree_id)?;
|
||||
let tree_id = self.builder.create_updated(&repo, &empty_tree)?;
|
||||
Ok(tree_id.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2737,7 +2737,7 @@ fn tree_to_file_list(repository: &git::Repository, tree: &git::Tree) -> Vec<Stri
|
||||
.get_path(std::path::Path::new(path))
|
||||
.unwrap_or_else(|_| panic!("failed to get tree entry for path {}", path));
|
||||
let object = entry
|
||||
.to_object(repository.into())
|
||||
.to_object(repository)
|
||||
.unwrap_or_else(|_| panic!("failed to get object for tree entry {}", path));
|
||||
if object.kind() == Some(git2::ObjectType::Blob) {
|
||||
file_list.push(path.to_string());
|
||||
@ -2759,7 +2759,7 @@ fn tree_to_entry_list(
|
||||
.get_path(std::path::Path::new(path))
|
||||
.unwrap_or_else(|_| panic!("failed to get tree entry for path {}", path));
|
||||
let object = entry
|
||||
.to_object(repository.into())
|
||||
.to_object(repository)
|
||||
.unwrap_or_else(|_| panic!("failed to get object for tree entry {}", path));
|
||||
let blob = object.as_blob().expect("failed to get blob");
|
||||
// convert content to string
|
||||
|
@ -1689,7 +1689,7 @@ pub fn write_tree(
|
||||
let head_commit = git_repository.find_commit(target.sha)?;
|
||||
let base_tree = head_commit.tree()?;
|
||||
|
||||
let mut builder = git2::build::TreeUpdateBuilder::new();
|
||||
let mut builder = git_repository.treebuilder(Some(&base_tree));
|
||||
// now update the index with content in the working directory for each file
|
||||
for file in files {
|
||||
// convert this string to a Path
|
||||
@ -1699,19 +1699,19 @@ pub fn write_tree(
|
||||
// if file exists
|
||||
if full_path.exists() {
|
||||
// if file is executable, use 755, otherwise 644
|
||||
let mut filemode = git2::FileMode::Blob;
|
||||
let mut filemode = git::FileMode::Blob;
|
||||
// check if full_path file is executable
|
||||
if let Ok(metadata) = std::fs::symlink_metadata(&full_path) {
|
||||
if metadata.permissions().mode() & 0o111 != 0 {
|
||||
filemode = git2::FileMode::BlobExecutable;
|
||||
filemode = git::FileMode::BlobExecutable;
|
||||
}
|
||||
if metadata.file_type().is_symlink() {
|
||||
filemode = git2::FileMode::Link;
|
||||
filemode = git::FileMode::Link;
|
||||
}
|
||||
}
|
||||
|
||||
// get the blob
|
||||
if filemode == git2::FileMode::Link {
|
||||
if filemode == git::FileMode::Link {
|
||||
// it's a symlink, make the content the path of the link
|
||||
let link_target = std::fs::read_link(&full_path)?;
|
||||
// make link_target into a relative path
|
||||
@ -1727,7 +1727,7 @@ pub fn write_tree(
|
||||
if file.binary {
|
||||
let new_blob_oid = &file.hunks[0].diff;
|
||||
// convert string to Oid
|
||||
let new_blob_oid = git2::Oid::from_str(new_blob_oid)?;
|
||||
let new_blob_oid = new_blob_oid.parse().context("failed to diff as oid")?;
|
||||
builder.upsert(rel_path, new_blob_oid, filemode);
|
||||
} else {
|
||||
// blob from tree_entry
|
||||
@ -1773,9 +1773,7 @@ pub fn write_tree(
|
||||
}
|
||||
|
||||
// now write out the tree
|
||||
let tree_oid = builder
|
||||
.create_updated(git_repository.into(), (&base_tree).into())
|
||||
.context("failed to create updated tree")?;
|
||||
let tree_oid = builder.write().context("failed to write updated tree")?;
|
||||
|
||||
Ok(tree_oid.into())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user