mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-11-28 22:03:30 +03:00
use git2::Oid
instead of String
; various small refactors
This commit is contained in:
parent
a5f71be44c
commit
590d713f91
@ -62,7 +62,7 @@ fn list_snapshots(repo_dir: &str) -> Result<()> {
|
||||
|
||||
fn restore_snapshot(repo_dir: &str, snapshot_id: &str) -> Result<()> {
|
||||
let project = project_from_path(repo_dir);
|
||||
project.restore_snapshot(snapshot_id.to_owned())?;
|
||||
project.restore_snapshot(snapshot_id.parse()?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ regex = "1.10"
|
||||
reqwest = { version = "0.12.4", features = ["json"] }
|
||||
resolve-path = "0.1.0"
|
||||
rusqlite.workspace = true
|
||||
serde.workspace = true
|
||||
serde = { workspace = true, features = ["std"]}
|
||||
serde_json = { version = "1.0", features = [ "std", "arbitrary_precision" ] }
|
||||
sha2 = "0.10.8"
|
||||
ssh-key = { version = "0.6.6", features = [ "alloc", "ed25519" ] }
|
||||
|
@ -63,4 +63,49 @@ pub mod serde {
|
||||
{
|
||||
v.seconds().serialize(s)
|
||||
}
|
||||
|
||||
pub mod oid_opt {
|
||||
use crate::git;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
|
||||
pub fn serialize<S>(v: &Option<git::Oid>, s: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
v.as_ref().map(|v| v.to_string()).serialize(s)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D>(d: D) -> Result<Option<git::Oid>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let hex = <Option<String> as Deserialize>::deserialize(d)?;
|
||||
hex.map(|v| {
|
||||
v.parse()
|
||||
.map_err(|err: git2::Error| serde::de::Error::custom(err.to_string()))
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
}
|
||||
|
||||
pub mod oid {
|
||||
use crate::git;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
|
||||
pub fn serialize<S>(v: &git::Oid, s: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
v.to_string().serialize(s)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D>(d: D) -> Result<git::Oid, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let hex = String::deserialize(d)?;
|
||||
hex.parse()
|
||||
.map_err(|err: git2::Error| serde::de::Error::custom(err.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use strum::EnumString;
|
||||
|
||||
use crate::git;
|
||||
use serde::Serialize;
|
||||
|
||||
/// A snapshot of the repository and virtual branches state that GitButler can restore to.
|
||||
@ -17,7 +18,8 @@ use serde::Serialize;
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Snapshot {
|
||||
/// The sha of the commit that represents the snapshot
|
||||
pub id: String,
|
||||
#[serde(with = "crate::serde::oid")]
|
||||
pub id: git::Oid,
|
||||
/// Snapshot creation time in seconds from Unix epoch seconds, based on a Git commit
|
||||
#[serde(serialize_with = "crate::serde::as_time_seconds_from_unix_epoch")]
|
||||
pub created_at: git2::Time,
|
||||
|
@ -4,4 +4,5 @@ mod reflog;
|
||||
pub mod snapshot;
|
||||
mod state;
|
||||
|
||||
/// The name of the file holding our state, useful for watching for changes.
|
||||
pub const OPLOG_FILE_NAME: &str = "operations-log.toml";
|
||||
|
@ -1,5 +1,5 @@
|
||||
use anyhow::anyhow;
|
||||
use git2::{FileMode, Oid};
|
||||
use git2::FileMode;
|
||||
use itertools::Itertools;
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
@ -11,7 +11,7 @@ use tracing::instrument;
|
||||
|
||||
use crate::git::diff::FileDiff;
|
||||
use crate::virtual_branches::Branch;
|
||||
use crate::{git::diff::hunks_by_filepath, projects::Project};
|
||||
use crate::{git, git::diff::hunks_by_filepath, projects::Project};
|
||||
|
||||
use super::{
|
||||
entry::{OperationKind, Snapshot, SnapshotDetails, Trailer},
|
||||
@ -38,7 +38,7 @@ impl Project {
|
||||
/// Prepares a snapshot of the current state of the working directory as well as GitButler data.
|
||||
/// Returns a tree sha of the snapshot. The snapshot is not discoverable until it is comitted with `commit_snapshot`
|
||||
/// If there are files that are untracked and larger than `SNAPSHOT_FILE_LIMIT_BYTES`, they are excluded from snapshot creation and restoring.
|
||||
pub(crate) fn prepare_snapshot(&self) -> Result<String> {
|
||||
pub(crate) fn prepare_snapshot(&self) -> Result<git::Oid> {
|
||||
let repo_path = self.path.as_path();
|
||||
let repo = git2::Repository::init(repo_path)?;
|
||||
|
||||
@ -68,7 +68,7 @@ impl Project {
|
||||
let mut tree_builder = repo.treebuilder(None)?;
|
||||
tree_builder.insert("index", index_tree_oid, FileMode::Tree.into())?;
|
||||
tree_builder.insert("target_tree", target_tree_oid, FileMode::Tree.into())?;
|
||||
tree_builder.insert("conflicts", conflicts_tree, FileMode::Tree.into())?;
|
||||
tree_builder.insert("conflicts", conflicts_tree.into(), FileMode::Tree.into())?;
|
||||
tree_builder.insert("virtual_branches.toml", vb_blob, FileMode::Blob.into())?;
|
||||
|
||||
// go through all virtual branches and create a subtree for each with the tree and any commits encoded
|
||||
@ -185,7 +185,7 @@ impl Project {
|
||||
let head_trees_iter = head_trees.iter();
|
||||
// iterate through all head trees
|
||||
for head_tree in head_trees_iter {
|
||||
let current_theirs = repo.find_tree(git2::Oid::from(*head_tree))?;
|
||||
let current_theirs = repo.find_tree((*head_tree).into())?;
|
||||
let mut workdir_temp_index =
|
||||
repo.merge_trees(&base_tree, ¤t_ours, ¤t_theirs, None)?;
|
||||
workdir_tree_oid = workdir_temp_index.write_tree_to(&repo)?;
|
||||
@ -196,7 +196,7 @@ impl Project {
|
||||
|
||||
// ok, write out the final oplog tree
|
||||
let tree_id = tree_builder.write()?;
|
||||
Ok(tree_id.to_string())
|
||||
Ok(tree_id.into())
|
||||
}
|
||||
|
||||
/// Commits the snapshot tree that is created with the `prepare_snapshot` method.
|
||||
@ -204,17 +204,17 @@ impl Project {
|
||||
/// Returns the sha of the created snapshot commit or None if snapshots are disabled.
|
||||
pub(crate) fn commit_snapshot(
|
||||
&self,
|
||||
tree_id: String,
|
||||
tree_id: git::Oid,
|
||||
details: SnapshotDetails,
|
||||
) -> Result<Option<String>> {
|
||||
) -> Result<Option<git::Oid>> {
|
||||
let repo_path = self.path.as_path();
|
||||
let repo = git2::Repository::init(repo_path)?;
|
||||
|
||||
let tree = repo.find_tree(Oid::from_str(&tree_id)?)?;
|
||||
let tree = repo.find_tree(tree_id.into())?;
|
||||
|
||||
let oplog_state = OplogHandle::new(&self.gb_dir());
|
||||
let oplog_head_commit = match oplog_state.get_oplog_head()? {
|
||||
Some(head_sha) => match repo.find_commit(git2::Oid::from_str(&head_sha)?) {
|
||||
Some(head_sha) => match repo.find_commit(head_sha.into()) {
|
||||
Ok(commit) => Some(commit),
|
||||
Err(_) => None, // cant find the old one, start over
|
||||
},
|
||||
@ -249,19 +249,15 @@ impl Project {
|
||||
parents.as_slice(),
|
||||
)?;
|
||||
|
||||
oplog_state.set_oplog_head(new_commit_oid.to_string())?;
|
||||
oplog_state.set_oplog_head(new_commit_oid.into())?;
|
||||
|
||||
let vb_state = self.virtual_branches();
|
||||
// grab the target tree sha
|
||||
let default_target_sha = vb_state.get_default_target()?.sha;
|
||||
|
||||
set_reference_to_oplog(
|
||||
self,
|
||||
&default_target_sha.to_string(),
|
||||
&new_commit_oid.to_string(),
|
||||
)?;
|
||||
set_reference_to_oplog(self, default_target_sha, new_commit_oid.into())?;
|
||||
|
||||
Ok(Some(new_commit_oid.to_string()))
|
||||
Ok(Some(new_commit_oid.into()))
|
||||
}
|
||||
|
||||
/// Creates a snapshot of the current state of the working directory as well as GitButler data.
|
||||
@ -269,7 +265,7 @@ impl Project {
|
||||
///
|
||||
/// Note that errors in snapshot creation is typically ignored, so we want to learn about them.
|
||||
#[instrument(skip(details), err(Debug))]
|
||||
pub fn create_snapshot(&self, details: SnapshotDetails) -> Result<Option<String>> {
|
||||
pub fn create_snapshot(&self, details: SnapshotDetails) -> Result<Option<git::Oid>> {
|
||||
let tree_id = self.prepare_snapshot()?;
|
||||
self.commit_snapshot(tree_id, details)
|
||||
}
|
||||
@ -278,7 +274,7 @@ impl Project {
|
||||
/// An alternative way of retrieving the snapshots would be to manually the oplog head `git log <oplog_head>` available in `.git/gitbutler/operations-log.toml`.
|
||||
///
|
||||
/// If there are no snapshots, an empty list is returned.
|
||||
pub fn list_snapshots(&self, limit: usize, sha: Option<String>) -> Result<Vec<Snapshot>> {
|
||||
pub fn list_snapshots(&self, limit: usize, sha: Option<git::Oid>) -> Result<Vec<Snapshot>> {
|
||||
let repo_path = self.path.as_path();
|
||||
let repo = git2::Repository::init(repo_path)?;
|
||||
|
||||
@ -295,7 +291,7 @@ impl Project {
|
||||
}
|
||||
};
|
||||
|
||||
let oplog_head_commit = repo.find_commit(git2::Oid::from_str(&head_sha)?)?;
|
||||
let oplog_head_commit = repo.find_commit(head_sha.into())?;
|
||||
|
||||
let mut revwalk = repo.revwalk()?;
|
||||
revwalk.push(oplog_head_commit.id())?;
|
||||
@ -345,7 +341,7 @@ impl Project {
|
||||
let lines_removed = stats.deletions();
|
||||
|
||||
snapshots.push(Snapshot {
|
||||
id: commit_id.to_string(),
|
||||
id: commit_id.into(),
|
||||
details,
|
||||
lines_added,
|
||||
lines_removed,
|
||||
@ -359,7 +355,7 @@ impl Project {
|
||||
} else {
|
||||
// this is the very first snapshot
|
||||
snapshots.push(Snapshot {
|
||||
id: commit_id.to_string(),
|
||||
id: commit_id.into(),
|
||||
details,
|
||||
lines_added: 0,
|
||||
lines_removed: 0,
|
||||
@ -384,14 +380,14 @@ impl Project {
|
||||
///
|
||||
/// If there are files that are untracked and larger than `SNAPSHOT_FILE_LIMIT_BYTES`, they are excluded from snapshot creation and restoring.
|
||||
/// Returns the sha of the created revert snapshot commit or None if snapshots are disabled.
|
||||
pub fn restore_snapshot(&self, sha: String) -> Result<Option<String>> {
|
||||
pub fn restore_snapshot(&self, sha: git::Oid) -> Result<Option<git::Oid>> {
|
||||
let repo_path = self.path.as_path();
|
||||
let repo = git2::Repository::init(repo_path)?;
|
||||
|
||||
// prepare snapshot
|
||||
let snapshot_tree = self.prepare_snapshot();
|
||||
|
||||
let commit = repo.find_commit(git2::Oid::from_str(&sha)?)?;
|
||||
let commit = repo.find_commit(sha.into())?;
|
||||
// Top tree
|
||||
let top_tree = commit.tree()?;
|
||||
let vb_tree_entry = top_tree
|
||||
@ -442,8 +438,8 @@ impl Project {
|
||||
// for each commit, recreate the commit from the commit data if it doesn't exist
|
||||
if let Some(commit_id) = commit_entry.name() {
|
||||
// check for the oid in the repo
|
||||
let commit_oid = git2::Oid::from_str(commit_id)?;
|
||||
if repo.find_commit(commit_oid).is_err() {
|
||||
let commit_oid = git::Oid::from_str(commit_id)?;
|
||||
if repo.find_commit(commit_oid.into()).is_err() {
|
||||
// commit is not in the repo, let's build it from our data
|
||||
// we get the data from the blob entry and create a commit object from it, which should match the oid of the entry
|
||||
let commit_tree = commit_entry
|
||||
@ -460,7 +456,7 @@ impl Project {
|
||||
let new_commit_oid = repo
|
||||
.odb()?
|
||||
.write(git2::ObjectType::Commit, commit_blob.content())?;
|
||||
if new_commit_oid != commit_oid {
|
||||
if new_commit_oid != commit_oid.into() {
|
||||
return Err(anyhow!("commit oid mismatch"));
|
||||
}
|
||||
}
|
||||
@ -468,13 +464,13 @@ impl Project {
|
||||
// if branch_name is 'integration', we need to create or update the gitbutler/integration branch
|
||||
if let Some(branch_name) = branch_name {
|
||||
if branch_name == "integration" {
|
||||
let integration_commit = repo.find_commit(commit_oid)?;
|
||||
let integration_commit = repo.find_commit(commit_oid.into())?;
|
||||
// reset the branch if it's there
|
||||
let branch =
|
||||
repo.find_branch("gitbutler/integration", git2::BranchType::Local);
|
||||
if let Ok(mut branch) = branch {
|
||||
// need to detatch the head for just a minuto
|
||||
repo.set_head_detached(commit_oid)?;
|
||||
repo.set_head_detached(commit_oid.into())?;
|
||||
branch.delete()?;
|
||||
}
|
||||
// ok, now we set the branch to what it was and update HEAD
|
||||
@ -538,7 +534,7 @@ impl Project {
|
||||
trailers: vec![
|
||||
Trailer {
|
||||
key: "restored_from".to_string(),
|
||||
value: sha,
|
||||
value: sha.to_string(),
|
||||
},
|
||||
Trailer {
|
||||
key: "restored_operation".to_string(),
|
||||
@ -580,11 +576,11 @@ impl Project {
|
||||
/// Returns the diff of the snapshot and it's parent. It only includes the workdir changes.
|
||||
///
|
||||
/// This is useful to show what has changed in this particular snapshot
|
||||
pub fn snapshot_diff(&self, sha: String) -> Result<HashMap<PathBuf, FileDiff>> {
|
||||
pub fn snapshot_diff(&self, sha: git::Oid) -> Result<HashMap<PathBuf, FileDiff>> {
|
||||
let repo_path = self.path.as_path();
|
||||
let repo = git2::Repository::init(repo_path)?;
|
||||
|
||||
let commit = repo.find_commit(git2::Oid::from_str(&sha)?)?;
|
||||
let commit = repo.find_commit(sha.into())?;
|
||||
// Top tree
|
||||
let tree = commit.tree()?;
|
||||
let old_tree = commit.parent(0)?.tree()?;
|
||||
@ -621,7 +617,7 @@ impl Project {
|
||||
}
|
||||
|
||||
/// Gets the sha of the last snapshot commit if present.
|
||||
pub fn oplog_head(&self) -> Result<Option<String>> {
|
||||
pub fn oplog_head(&self) -> Result<Option<git::Oid>> {
|
||||
let oplog_state = OplogHandle::new(&self.gb_dir());
|
||||
oplog_state.get_oplog_head()
|
||||
}
|
||||
@ -663,7 +659,7 @@ fn restore_conflicts_tree(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_conflicts_tree(repo_path: &std::path::Path, repo: &git2::Repository) -> Result<git2::Oid> {
|
||||
fn write_conflicts_tree(repo_path: &std::path::Path, repo: &git2::Repository) -> Result<git::Oid> {
|
||||
let merge_parent_path = repo_path.join(".git").join("base_merge_parent");
|
||||
let merge_parent_blob = if merge_parent_path.exists() {
|
||||
let merge_parent_content = fs::read(merge_parent_path)?;
|
||||
@ -690,7 +686,7 @@ fn write_conflicts_tree(repo_path: &std::path::Path, repo: &git2::Repository) ->
|
||||
tree_builder.insert("conflicts", conflicts_blob.unwrap(), FileMode::Blob.into())?;
|
||||
}
|
||||
let conflicts_tree = tree_builder.write()?;
|
||||
Ok(conflicts_tree)
|
||||
Ok(conflicts_tree.into())
|
||||
}
|
||||
|
||||
fn get_exclude_list(repo: &git2::Repository) -> Result<String> {
|
||||
@ -740,11 +736,9 @@ fn lines_since_snapshot(project: &Project) -> Result<usize> {
|
||||
repo.add_ignore_rule(&files_to_exclude)?;
|
||||
|
||||
let oplog_state = OplogHandle::new(&project.gb_dir());
|
||||
let head_sha = oplog_state.get_oplog_head()?;
|
||||
if head_sha.is_none() {
|
||||
let Some(head_sha) = oplog_state.get_oplog_head()? else {
|
||||
return Ok(0);
|
||||
}
|
||||
let head_sha = head_sha.unwrap();
|
||||
};
|
||||
|
||||
let vb_state = project.virtual_branches();
|
||||
let binding = vb_state.list_branches()?;
|
||||
@ -757,7 +751,7 @@ fn lines_since_snapshot(project: &Project) -> Result<usize> {
|
||||
|
||||
let mut lines_changed = 0;
|
||||
for branch in dirty_branches {
|
||||
lines_changed += branch_lines_since_snapshot(branch, &repo, head_sha.clone())?;
|
||||
lines_changed += branch_lines_since_snapshot(branch, &repo, head_sha)?;
|
||||
}
|
||||
Ok(lines_changed)
|
||||
}
|
||||
@ -765,11 +759,11 @@ fn lines_since_snapshot(project: &Project) -> Result<usize> {
|
||||
fn branch_lines_since_snapshot(
|
||||
branch: &Branch,
|
||||
repo: &git2::Repository,
|
||||
head_sha: String,
|
||||
head_sha: git::Oid,
|
||||
) -> Result<usize> {
|
||||
let active_branch_tree = repo.find_tree(branch.tree.into())?;
|
||||
|
||||
let commit = repo.find_commit(git2::Oid::from_str(&head_sha)?)?;
|
||||
let commit = repo.find_commit(head_sha.into())?;
|
||||
let head_tree = commit.tree()?;
|
||||
let virtual_branches = head_tree
|
||||
.get_name("virtual_branches")
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::fs::write;
|
||||
use crate::git;
|
||||
use anyhow::Result;
|
||||
use itertools::Itertools;
|
||||
use std::path::PathBuf;
|
||||
@ -22,8 +23,8 @@ use crate::projects::Project;
|
||||
/// The reflog entry is continuously updated to refer to the current target and oplog head commits.
|
||||
pub(crate) fn set_reference_to_oplog(
|
||||
project: &Project,
|
||||
target_head_sha: &str,
|
||||
oplog_head_sha: &str,
|
||||
target_head_sha: git::Oid,
|
||||
oplog_head_sha: git::Oid,
|
||||
) -> Result<()> {
|
||||
let repo_path = project.path.as_path();
|
||||
let reflog_file_path = repo_path
|
||||
@ -36,7 +37,7 @@ pub(crate) fn set_reference_to_oplog(
|
||||
|
||||
if !reflog_file_path.exists() {
|
||||
let repo = git2::Repository::init(repo_path)?;
|
||||
let commit = repo.find_commit(git2::Oid::from_str(target_head_sha)?)?;
|
||||
let commit = repo.find_commit(target_head_sha.into())?;
|
||||
repo.branch("gitbutler/target", &commit, false)?;
|
||||
}
|
||||
|
||||
@ -46,8 +47,8 @@ pub(crate) fn set_reference_to_oplog(
|
||||
));
|
||||
}
|
||||
|
||||
set_target_ref(&reflog_file_path, target_head_sha)?;
|
||||
set_oplog_ref(&reflog_file_path, oplog_head_sha)?;
|
||||
set_target_ref(&reflog_file_path, &target_head_sha.to_string())?;
|
||||
set_oplog_ref(&reflog_file_path, &oplog_head_sha.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -88,6 +89,7 @@ fn set_oplog_ref(file_path: &PathBuf, sha: &str) -> Result<()> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::str::FromStr;
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[test]
|
||||
@ -109,7 +111,8 @@ mod tests {
|
||||
assert!(!log_file_path.exists());
|
||||
|
||||
// Set ref for the first time
|
||||
assert!(set_reference_to_oplog(&project, &commit_id.to_string(), "oplog_sha").is_ok());
|
||||
let oplog_sha = git::Oid::from_str("0123456789abcdef0123456789abcdef0123456").unwrap();
|
||||
assert!(set_reference_to_oplog(&project, commit_id.into(), oplog_sha).is_ok());
|
||||
assert!(log_file_path.exists());
|
||||
let log_file = std::fs::read_to_string(&log_file_path).unwrap();
|
||||
let log_lines = log_file.lines().collect::<Vec<_>>();
|
||||
@ -119,13 +122,12 @@ mod tests {
|
||||
commit_id
|
||||
)));
|
||||
assert!(log_lines[0].ends_with(&format!("branch: Created from {}", commit_id)));
|
||||
assert!(log_lines[1].starts_with(&format!("{} {}", commit_id, "oplog_sha")));
|
||||
assert!(log_lines[1].ends_with("reset: moving to oplog_sha"));
|
||||
assert!(log_lines[1].starts_with(&format!("{} {}", commit_id, oplog_sha)));
|
||||
assert!(log_lines[1].ends_with(&format!("reset: moving to {oplog_sha}")));
|
||||
|
||||
// Update the oplog head only
|
||||
assert!(
|
||||
set_reference_to_oplog(&project, &commit_id.to_string(), "another_oplog_sha").is_ok()
|
||||
);
|
||||
let another_oplog_sha = git2::Oid::zero().into();
|
||||
assert!(set_reference_to_oplog(&project, commit_id.into(), another_oplog_sha).is_ok());
|
||||
let log_file = std::fs::read_to_string(&log_file_path).unwrap();
|
||||
let log_lines = log_file.lines().collect::<Vec<_>>();
|
||||
assert_eq!(log_lines.len(), 2);
|
||||
@ -134,23 +136,21 @@ mod tests {
|
||||
commit_id
|
||||
)));
|
||||
assert!(log_lines[0].ends_with(&format!("branch: Created from {}", commit_id)));
|
||||
println!("{:?}", log_lines[1]);
|
||||
assert!(log_lines[1].starts_with(&format!("{} {}", commit_id, "another_oplog_sha")));
|
||||
assert!(log_lines[1].ends_with("reset: moving to another_oplog_sha"));
|
||||
assert!(log_lines[1].starts_with(&format!("{} {}", commit_id, another_oplog_sha)));
|
||||
assert!(log_lines[1].ends_with(&format!("reset: moving to {another_oplog_sha}")));
|
||||
|
||||
// Update the target head only
|
||||
assert!(set_reference_to_oplog(&project, "new_target", "another_oplog_sha").is_ok());
|
||||
let new_target = git::Oid::from_str("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").unwrap();
|
||||
assert!(set_reference_to_oplog(&project, new_target, another_oplog_sha).is_ok());
|
||||
let log_file = std::fs::read_to_string(&log_file_path).unwrap();
|
||||
let log_lines = log_file.lines().collect::<Vec<_>>();
|
||||
assert_eq!(log_lines.len(), 2);
|
||||
assert!(log_lines[0].starts_with(&format!(
|
||||
"0000000000000000000000000000000000000000 {}",
|
||||
"new_target"
|
||||
"0000000000000000000000000000000000000000 {new_target}"
|
||||
)));
|
||||
assert!(log_lines[0].ends_with(&format!("branch: Created from {}", "new_target")));
|
||||
println!("{:?}", log_lines[1]);
|
||||
assert!(log_lines[1].starts_with(&format!("{} {}", "new_target", "another_oplog_sha")));
|
||||
assert!(log_lines[1].ends_with("reset: moving to another_oplog_sha"));
|
||||
assert!(log_lines[0].ends_with(&format!("branch: Created from {new_target}")));
|
||||
assert!(log_lines[1].starts_with(&format!("{new_target} {another_oplog_sha}")));
|
||||
assert!(log_lines[1].ends_with(&format!("reset: moving to {another_oplog_sha}")));
|
||||
}
|
||||
|
||||
fn setup_repo() -> (tempfile::TempDir, git2::Oid) {
|
||||
|
@ -2,6 +2,7 @@ use std::vec;
|
||||
|
||||
use crate::projects::Project;
|
||||
use crate::{
|
||||
git,
|
||||
ops::entry::{OperationKind, SnapshotDetails},
|
||||
virtual_branches::{branch::BranchUpdateRequest, Branch},
|
||||
};
|
||||
@ -28,20 +29,20 @@ impl Project {
|
||||
self.create_snapshot(details)?;
|
||||
Ok(())
|
||||
}
|
||||
pub(crate) fn snapshot_commit_undo(&self, commit_sha: String) -> anyhow::Result<()> {
|
||||
pub(crate) fn snapshot_commit_undo(&self, commit_sha: git::Oid) -> anyhow::Result<()> {
|
||||
let details =
|
||||
SnapshotDetails::new(OperationKind::UndoCommit).with_trailers(vec![Trailer {
|
||||
key: "sha".to_string(),
|
||||
value: commit_sha,
|
||||
value: commit_sha.to_string(),
|
||||
}]);
|
||||
self.create_snapshot(details)?;
|
||||
Ok(())
|
||||
}
|
||||
pub(crate) fn snapshot_commit_creation(
|
||||
&self,
|
||||
snapshot_tree: String,
|
||||
snapshot_tree: git::Oid,
|
||||
commit_message: String,
|
||||
sha: Option<String>,
|
||||
sha: Option<git::Oid>,
|
||||
) -> anyhow::Result<()> {
|
||||
let details = SnapshotDetails::new(OperationKind::CreateCommit).with_trailers(vec![
|
||||
Trailer {
|
||||
@ -50,7 +51,7 @@ impl Project {
|
||||
},
|
||||
Trailer {
|
||||
key: "sha".to_string(),
|
||||
value: sha.unwrap_or_default(),
|
||||
value: sha.map(|sha| sha.to_string()).unwrap_or_default(),
|
||||
},
|
||||
]);
|
||||
self.commit_snapshot(snapshot_tree, details)?;
|
||||
|
@ -5,6 +5,7 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::fs::read_toml_file_or_default;
|
||||
use crate::git;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
|
||||
use super::OPLOG_FILE_NAME;
|
||||
@ -26,7 +27,8 @@ fn unix_epoch() -> SystemTime {
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Oplog {
|
||||
/// This is the sha of the last oplog commit
|
||||
pub head_sha: Option<String>,
|
||||
#[serde(with = "crate::serde::oid_opt")]
|
||||
pub head_sha: Option<git::Oid>,
|
||||
/// The time when the last snapshot was created. Seconds since Epoch
|
||||
#[serde(
|
||||
deserialize_with = "unfailing_system_time_deserialize",
|
||||
@ -59,7 +61,7 @@ impl OplogHandle {
|
||||
/// Persists the oplog head for the given repository.
|
||||
///
|
||||
/// Errors if the file cannot be read or written.
|
||||
pub fn set_oplog_head(&self, sha: String) -> Result<()> {
|
||||
pub fn set_oplog_head(&self, sha: git::Oid) -> Result<()> {
|
||||
let mut oplog = self.read_file()?;
|
||||
oplog.head_sha = Some(sha);
|
||||
self.write_file(oplog)?;
|
||||
@ -69,7 +71,7 @@ impl OplogHandle {
|
||||
/// Gets the oplog head sha for the given repository.
|
||||
///
|
||||
/// Errors if the file cannot be read or written.
|
||||
pub fn get_oplog_head(&self) -> Result<Option<String>> {
|
||||
pub fn get_oplog_head(&self) -> Result<Option<git::Oid>> {
|
||||
let oplog = self.read_file()?;
|
||||
Ok(oplog.head_sha)
|
||||
}
|
||||
|
@ -460,7 +460,7 @@ impl ControllerInner {
|
||||
project_repository.project().snapshot_commit_creation(
|
||||
snapshot_tree,
|
||||
message.to_owned(),
|
||||
Some("".to_string()),
|
||||
None,
|
||||
)
|
||||
});
|
||||
result
|
||||
@ -717,7 +717,7 @@ impl ControllerInner {
|
||||
self.with_verify_branch(project_id, |project_repository, _| {
|
||||
let _ = project_repository
|
||||
.project()
|
||||
.snapshot_commit_undo(commit_oid.to_string());
|
||||
.snapshot_commit_undo(commit_oid);
|
||||
super::undo_commit(project_repository, branch_id, commit_oid).map_err(Into::into)
|
||||
})
|
||||
}
|
||||
|
@ -88,14 +88,14 @@ mod snapshot_details {
|
||||
|
||||
#[test]
|
||||
fn new() {
|
||||
let commit_sha = "1234567890".to_string();
|
||||
let commit_sha = git2::Oid::zero().into();
|
||||
let commit_message =
|
||||
"Create a new snapshot\n\nBody text 1\nBody text2\n\nBody text 3\n\nVersion: 1\nOperation: CreateCommit\nFoo: Bar\n".to_string();
|
||||
let timezone_offset_does_not_matter = 1234;
|
||||
let created_at = git2::Time::new(1234567890, timezone_offset_does_not_matter);
|
||||
let details = SnapshotDetails::from_str(&commit_message.clone()).unwrap();
|
||||
let snapshot = Snapshot {
|
||||
id: commit_sha.clone(),
|
||||
id: commit_sha,
|
||||
created_at,
|
||||
lines_added: 1,
|
||||
lines_removed: 1,
|
||||
|
@ -157,7 +157,6 @@ mod go_back_to_integration {
|
||||
controller
|
||||
.set_base_branch(project_id, &"refs/remotes/origin/master".parse().unwrap())
|
||||
.await
|
||||
.map_err(|error| dbg!(error))
|
||||
.unwrap_err()
|
||||
.downcast_ref(),
|
||||
Some(errors::SetBaseBranchError::DirtyWorkingDirectory)
|
||||
|
@ -22,7 +22,11 @@ pub async fn list_snapshots(
|
||||
.state::<projects::Controller>()
|
||||
.get(&project_id)
|
||||
.context("failed to get project")?;
|
||||
let snapshots = project.list_snapshots(limit, sha)?;
|
||||
let snapshots = project.list_snapshots(
|
||||
limit,
|
||||
sha.map(|hex| hex.parse().map_err(anyhow::Error::from))
|
||||
.transpose()?,
|
||||
)?;
|
||||
Ok(snapshots)
|
||||
}
|
||||
|
||||
@ -37,7 +41,7 @@ pub async fn restore_snapshot(
|
||||
.state::<projects::Controller>()
|
||||
.get(&project_id)
|
||||
.context("failed to get project")?;
|
||||
project.restore_snapshot(sha)?;
|
||||
project.restore_snapshot(sha.parse().map_err(anyhow::Error::from)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -52,6 +56,6 @@ pub async fn snapshot_diff(
|
||||
.state::<projects::Controller>()
|
||||
.get(&project_id)
|
||||
.context("failed to get project")?;
|
||||
let diff = project.snapshot_diff(sha)?;
|
||||
let diff = project.snapshot_diff(sha.parse().map_err(anyhow::Error::from)?)?;
|
||||
Ok(diff)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user