mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2025-01-06 01:27:24 +03:00
typed virtual branch id
This commit is contained in:
parent
a589b934a2
commit
8accaa1fec
@ -20,7 +20,7 @@ impl super::RunCommand for Branches {
|
||||
.context("failed to list branches")?;
|
||||
|
||||
for branch in branches {
|
||||
println!("{}", branch.id.red());
|
||||
println!("{}", branch.id.to_string().red());
|
||||
println!("{}", branch.name.red());
|
||||
for file in branch.files {
|
||||
println!(" {}", file.path.display().to_string().blue());
|
||||
|
@ -48,7 +48,10 @@ impl super::RunCommand for Commit {
|
||||
};
|
||||
|
||||
let commit_branch = ids[selection].clone();
|
||||
println!("Committing virtual branch {}", commit_branch.red());
|
||||
println!(
|
||||
"Committing virtual branch {}",
|
||||
commit_branch.to_string().red()
|
||||
);
|
||||
|
||||
// get the commit message
|
||||
let message: String = Input::with_theme(&ColorfulTheme::default())
|
||||
|
@ -22,7 +22,7 @@ impl super::RunCommand for Status {
|
||||
println!(" branch: {}", branch.name.blue());
|
||||
println!(" head: {}", branch.head.to_string().green());
|
||||
println!(" tree: {}", branch.tree.to_string().green());
|
||||
println!(" id: {}", branch.id.green());
|
||||
println!(" id: {}", branch.id.to_string().green());
|
||||
println!("applied: {}", branch.applied.to_string().green());
|
||||
println!(" files:");
|
||||
for file in files {
|
||||
|
@ -6,6 +6,7 @@ use serde::{ser::SerializeMap, Serialize};
|
||||
pub enum Code {
|
||||
Unknown,
|
||||
Sessions,
|
||||
Branches,
|
||||
Projects,
|
||||
ProjectGitAuth,
|
||||
ProjectGitRemote,
|
||||
@ -17,6 +18,7 @@ impl fmt::Display for Code {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Code::Unknown => write!(f, "errors.unknown"),
|
||||
Code::Branches => write!(f, "errors.branches"),
|
||||
Code::Sessions => write!(f, "errors.sessions"),
|
||||
Code::Projects => write!(f, "errors.projects"),
|
||||
Code::ProjectGitAuth => write!(f, "errors.projects.git.auth"),
|
||||
|
@ -11,6 +11,18 @@ impl<T> Hash for Id<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PartialOrd for Id<T> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Ord for Id<T> {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.0.cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Id<T> {
|
||||
pub fn generate() -> Self {
|
||||
Id(Uuid::new_v4(), PhantomData)
|
||||
|
@ -2,7 +2,6 @@ use std::time;
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
use serde::Serialize;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
gb_repository,
|
||||
@ -11,7 +10,7 @@ use crate::{
|
||||
reader, sessions, users,
|
||||
};
|
||||
|
||||
use super::{branch, delete_branch, iterator, target, RemoteCommit};
|
||||
use super::{branch, delete_branch, iterator, target, BranchId, RemoteCommit};
|
||||
|
||||
#[derive(Debug, Serialize, PartialEq, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@ -540,9 +539,8 @@ pub fn create_virtual_branch_from_branch(
|
||||
}
|
||||
};
|
||||
|
||||
let branch_id = Uuid::new_v4().to_string();
|
||||
let mut branch = branch::Branch {
|
||||
id: branch_id.clone(),
|
||||
id: BranchId::generate(),
|
||||
name: upstream.branch().to_string(),
|
||||
notes: String::new(),
|
||||
applied: applied.unwrap_or(false),
|
||||
|
@ -16,7 +16,9 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::git;
|
||||
use crate::{git, id::Id};
|
||||
|
||||
pub type BranchId = Id<Branch>;
|
||||
|
||||
// this is the struct for the virtual branch data that is stored in our data
|
||||
// store. it is more or less equivalent to a git branch reference, but it is not
|
||||
@ -24,7 +26,7 @@ use crate::git;
|
||||
// session storage under the branches/ directory.
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Branch {
|
||||
pub id: String,
|
||||
pub id: BranchId,
|
||||
pub name: String,
|
||||
pub notes: String,
|
||||
pub applied: bool,
|
||||
@ -43,7 +45,7 @@ pub struct Branch {
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct BranchUpdateRequest {
|
||||
pub id: String,
|
||||
pub id: BranchId,
|
||||
pub name: Option<String>,
|
||||
pub notes: Option<String>,
|
||||
pub ownership: Option<Ownership>,
|
||||
@ -63,6 +65,12 @@ impl TryFrom<&dyn crate::reader::Reader> for Branch {
|
||||
|
||||
fn try_from(reader: &dyn crate::reader::Reader) -> Result<Self, Self::Error> {
|
||||
let id: String = reader.read(&path::PathBuf::from("id"))?.try_into()?;
|
||||
let id: BranchId = id.parse().map_err(|e| {
|
||||
crate::reader::Error::Io(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!("id: {}", e),
|
||||
))
|
||||
})?;
|
||||
let name: String = reader.read(&path::PathBuf::from("meta/name"))?.try_into()?;
|
||||
|
||||
let notes: String = match reader.read(&path::PathBuf::from("meta/notes")) {
|
||||
|
@ -2,7 +2,7 @@ use std::path;
|
||||
|
||||
use crate::reader::{self, Reader, SubReader};
|
||||
|
||||
use super::Branch;
|
||||
use super::{Branch, BranchId};
|
||||
|
||||
pub struct BranchReader<'reader> {
|
||||
reader: &'reader dyn reader::Reader,
|
||||
@ -17,7 +17,7 @@ impl<'reader> BranchReader<'reader> {
|
||||
self.reader
|
||||
}
|
||||
|
||||
pub fn read(&self, id: &str) -> Result<Branch, reader::Error> {
|
||||
pub fn read(&self, id: &BranchId) -> Result<Branch, reader::Error> {
|
||||
if !self
|
||||
.reader
|
||||
.exists(&path::PathBuf::from(format!("branches/{}", id)))
|
||||
@ -52,7 +52,7 @@ mod tests {
|
||||
TEST_INDEX.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
Branch {
|
||||
id: format!("branch_{}", TEST_INDEX.load(Ordering::Relaxed)),
|
||||
id: BranchId::generate(),
|
||||
name: format!("branch_name_{}", TEST_INDEX.load(Ordering::Relaxed)),
|
||||
notes: "".to_string(),
|
||||
applied: true,
|
||||
@ -103,7 +103,7 @@ mod tests {
|
||||
let session_reader = sessions::Reader::open(&gb_repository, &session)?;
|
||||
|
||||
let reader = BranchReader::new(&session_reader);
|
||||
let result = reader.read("not found");
|
||||
let result = reader.read(&BranchId::generate());
|
||||
assert!(result.is_err());
|
||||
assert_eq!(result.unwrap_err().to_string(), "file not found");
|
||||
|
||||
|
@ -34,7 +34,10 @@ impl<'writer> BranchWriter<'writer> {
|
||||
let _lock = self.repository.lock();
|
||||
|
||||
self.writer
|
||||
.write_string(&format!("branches/{}/id", branch.id), &branch.id)
|
||||
.write_string(
|
||||
&format!("branches/{}/id", branch.id),
|
||||
&branch.id.to_string(),
|
||||
)
|
||||
.context("Failed to write branch id")?;
|
||||
|
||||
self.writer
|
||||
@ -121,6 +124,8 @@ mod tests {
|
||||
virtual_branches::branch,
|
||||
};
|
||||
|
||||
use self::branch::BranchId;
|
||||
|
||||
use super::*;
|
||||
|
||||
static TEST_INDEX: Lazy<AtomicUsize> = Lazy::new(|| AtomicUsize::new(0));
|
||||
@ -129,7 +134,7 @@ mod tests {
|
||||
TEST_INDEX.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
Branch {
|
||||
id: format!("branch_{}", TEST_INDEX.load(Ordering::Relaxed)),
|
||||
id: BranchId::generate(),
|
||||
name: format!("branch_name_{}", TEST_INDEX.load(Ordering::Relaxed)),
|
||||
notes: "".to_string(),
|
||||
applied: true,
|
||||
@ -175,7 +180,10 @@ mod tests {
|
||||
let writer = BranchWriter::new(&gb_repository);
|
||||
writer.write(&branch)?;
|
||||
|
||||
let root = gb_repository.root().join("branches").join(&branch.id);
|
||||
let root = gb_repository
|
||||
.root()
|
||||
.join("branches")
|
||||
.join(branch.id.to_string());
|
||||
|
||||
assert_eq!(
|
||||
fs::read_to_string(root.join("meta").join("name").to_str().unwrap())
|
||||
@ -259,7 +267,10 @@ mod tests {
|
||||
|
||||
writer.write(&updated_branch)?;
|
||||
|
||||
let root = gb_repository.root().join("branches").join(&branch.id);
|
||||
let root = gb_repository
|
||||
.root()
|
||||
.join("branches")
|
||||
.join(branch.id.to_string());
|
||||
|
||||
assert_eq!(
|
||||
fs::read_to_string(root.join("meta").join("name").to_str().unwrap())
|
||||
|
@ -9,7 +9,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
branch::Ownership,
|
||||
branch::{BranchId, Ownership},
|
||||
controller::{self, Controller},
|
||||
RemoteBranchFile,
|
||||
};
|
||||
@ -46,9 +46,13 @@ pub async fn commit_virtual_branch(
|
||||
code: Code::Projects,
|
||||
message: "Malformed project id".to_string(),
|
||||
})?;
|
||||
let branch_id = branch.parse().map_err(|_| Error::UserError {
|
||||
code: Code::Branches,
|
||||
message: "Malformed branch id".to_string(),
|
||||
})?;
|
||||
handle
|
||||
.state::<Controller>()
|
||||
.create_commit(&project_id, branch, message, ownership.as_ref())
|
||||
.create_commit(&project_id, &branch_id, message, ownership.as_ref())
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
@ -76,7 +80,7 @@ pub async fn create_virtual_branch(
|
||||
handle: AppHandle,
|
||||
project_id: &str,
|
||||
branch: super::branch::BranchCreateRequest,
|
||||
) -> Result<String, Error> {
|
||||
) -> Result<BranchId, Error> {
|
||||
let project_id = project_id.parse().map_err(|_| Error::UserError {
|
||||
code: Code::Projects,
|
||||
message: "Malformed project id".to_string(),
|
||||
@ -94,7 +98,7 @@ pub async fn create_virtual_branch_from_branch(
|
||||
handle: AppHandle,
|
||||
project_id: &str,
|
||||
branch: git::BranchName,
|
||||
) -> Result<String, Error> {
|
||||
) -> Result<BranchId, Error> {
|
||||
let project_id = project_id.parse().map_err(|_| Error::UserError {
|
||||
code: Code::Projects,
|
||||
message: "Malformed project id".to_string(),
|
||||
@ -117,9 +121,13 @@ pub async fn merge_virtual_branch_upstream(
|
||||
code: Code::Projects,
|
||||
message: "Malformed project id".to_string(),
|
||||
})?;
|
||||
let branch_id = branch.parse().map_err(|_| Error::UserError {
|
||||
code: Code::Branches,
|
||||
message: "Malformed branch id".to_string(),
|
||||
})?;
|
||||
handle
|
||||
.state::<Controller>()
|
||||
.merge_virtual_branch_upstream(&project_id, branch)
|
||||
.merge_virtual_branch_upstream(&project_id, &branch_id)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
@ -213,9 +221,13 @@ pub async fn delete_virtual_branch(
|
||||
code: Code::Projects,
|
||||
message: "Malformed project id".to_string(),
|
||||
})?;
|
||||
let branch_id = branch_id.parse().map_err(|_| Error::UserError {
|
||||
code: Code::Branches,
|
||||
message: "Malformed branch id".to_string(),
|
||||
})?;
|
||||
handle
|
||||
.state::<Controller>()
|
||||
.delete_virtual_branch(&project_id, branch_id)
|
||||
.delete_virtual_branch(&project_id, &branch_id)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
@ -227,9 +239,13 @@ pub async fn apply_branch(handle: AppHandle, project_id: &str, branch: &str) ->
|
||||
code: Code::Projects,
|
||||
message: "Malformed project id".to_string(),
|
||||
})?;
|
||||
let branch_id = branch.parse().map_err(|_| Error::UserError {
|
||||
code: Code::Branches,
|
||||
message: "Malformed branch id".to_string(),
|
||||
})?;
|
||||
handle
|
||||
.state::<Controller>()
|
||||
.apply_virtual_branch(&project_id, branch)
|
||||
.apply_virtual_branch(&project_id, &branch_id)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
@ -245,9 +261,13 @@ pub async fn unapply_branch(
|
||||
code: Code::Projects,
|
||||
message: "Malformed project id".to_string(),
|
||||
})?;
|
||||
let branch_id = branch.parse().map_err(|_| Error::UserError {
|
||||
code: Code::Branches,
|
||||
message: "Malformed branch id".to_string(),
|
||||
})?;
|
||||
handle
|
||||
.state::<Controller>()
|
||||
.unapply_virtual_branch(&project_id, branch)
|
||||
.unapply_virtual_branch(&project_id, &branch_id)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
@ -282,9 +302,13 @@ pub async fn push_virtual_branch(
|
||||
code: Code::Projects,
|
||||
message: "Malformed project id".to_string(),
|
||||
})?;
|
||||
let branch_id = branch_id.parse().map_err(|_| Error::UserError {
|
||||
code: Code::Branches,
|
||||
message: "Malformed branch id".to_string(),
|
||||
})?;
|
||||
handle
|
||||
.state::<Controller>()
|
||||
.push_virtual_branch(&project_id, branch_id, with_force)
|
||||
.push_virtual_branch(&project_id, &branch_id, with_force)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
@ -300,9 +324,13 @@ pub async fn can_apply_virtual_branch(
|
||||
code: Code::Projects,
|
||||
message: "Malformed project id".to_string(),
|
||||
})?;
|
||||
let branch_id = branch_id.parse().map_err(|_| Error::UserError {
|
||||
code: Code::Branches,
|
||||
message: "Malformed branch id".to_string(),
|
||||
})?;
|
||||
handle
|
||||
.state::<Controller>()
|
||||
.can_apply_virtual_branch(&project_id, branch_id)
|
||||
.can_apply_virtual_branch(&project_id, &branch_id)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
@ -352,9 +380,13 @@ pub async fn reset_virtual_branch(
|
||||
code: Code::Projects,
|
||||
message: "Malformed project id".to_string(),
|
||||
})?;
|
||||
let branch_id = branch_id.parse().map_err(|_| Error::UserError {
|
||||
code: Code::Branches,
|
||||
message: "Malformed branch id".to_string(),
|
||||
})?;
|
||||
handle
|
||||
.state::<Controller>()
|
||||
.reset_virtual_branch(&project_id, branch_id, target_commit_oid)
|
||||
.reset_virtual_branch(&project_id, &branch_id, target_commit_oid)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
@ -12,7 +12,10 @@ use crate::{
|
||||
users,
|
||||
};
|
||||
|
||||
use super::{branch::Ownership, RemoteBranchFile};
|
||||
use super::{
|
||||
branch::{BranchId, Ownership},
|
||||
RemoteBranchFile,
|
||||
};
|
||||
|
||||
pub struct Controller {
|
||||
local_data_dir: DataDir,
|
||||
@ -86,7 +89,7 @@ impl Controller {
|
||||
pub async fn create_commit(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch: &str,
|
||||
branch_id: &BranchId,
|
||||
message: &str,
|
||||
ownership: Option<&Ownership>,
|
||||
) -> Result<git::Oid, Error> {
|
||||
@ -108,7 +111,7 @@ impl Controller {
|
||||
super::commit(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
branch,
|
||||
branch_id,
|
||||
message,
|
||||
ownership,
|
||||
signing_key.as_ref(),
|
||||
@ -144,7 +147,7 @@ impl Controller {
|
||||
pub fn can_apply_virtual_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &str,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<bool, Error> {
|
||||
let project = self.projects.get(project_id)?;
|
||||
let project_repository = project_repository::Repository::try_from(&project)?;
|
||||
@ -176,7 +179,7 @@ impl Controller {
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
create: &super::branch::BranchCreateRequest,
|
||||
) -> Result<String, Error> {
|
||||
) -> Result<BranchId, Error> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
if conflicts::is_resolving(project_repository) {
|
||||
@ -195,8 +198,8 @@ impl Controller {
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch: &git::BranchName,
|
||||
) -> Result<String, Error> {
|
||||
self.with_lock::<Result<String, Error>>(project_id, || {
|
||||
) -> Result<BranchId, Error> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, user| {
|
||||
let branch = super::create_virtual_branch_from_branch(
|
||||
gb_repository,
|
||||
@ -300,7 +303,7 @@ impl Controller {
|
||||
pub async fn merge_virtual_branch_upstream(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch: &str,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<(), Error> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, user| {
|
||||
@ -326,7 +329,7 @@ impl Controller {
|
||||
super::merge_virtual_branch_upstream(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
branch,
|
||||
branch_id,
|
||||
signing_key.as_ref(),
|
||||
user,
|
||||
)
|
||||
@ -363,7 +366,7 @@ impl Controller {
|
||||
pub async fn delete_virtual_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &str,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<(), Error> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
@ -377,7 +380,7 @@ impl Controller {
|
||||
pub async fn apply_virtual_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &str,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<(), Error> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, user| {
|
||||
@ -424,7 +427,7 @@ impl Controller {
|
||||
pub async fn reset_virtual_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &str,
|
||||
branch_id: &BranchId,
|
||||
target_commit_oid: git::Oid,
|
||||
) -> Result<(), Error> {
|
||||
self.with_lock(project_id, || {
|
||||
@ -444,7 +447,7 @@ impl Controller {
|
||||
pub async fn unapply_virtual_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &str,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<(), Error> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
@ -458,7 +461,7 @@ impl Controller {
|
||||
pub async fn push_virtual_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &str,
|
||||
branch_id: &BranchId,
|
||||
with_force: bool,
|
||||
) -> Result<(), Error> {
|
||||
self.with_lock(project_id, || {
|
||||
|
@ -4,11 +4,11 @@ use anyhow::Result;
|
||||
|
||||
use crate::reader;
|
||||
|
||||
use super::branch;
|
||||
use super::branch::{self, BranchId};
|
||||
|
||||
pub struct BranchIterator<'iterator> {
|
||||
branch_reader: branch::Reader<'iterator>,
|
||||
ids: Vec<String>,
|
||||
ids: Vec<BranchId>,
|
||||
}
|
||||
|
||||
impl<'iterator> BranchIterator<'iterator> {
|
||||
@ -28,7 +28,11 @@ impl<'iterator> BranchIterator<'iterator> {
|
||||
.filter(|file_path| file_path != "selected")
|
||||
.filter(|file_path| file_path != "target");
|
||||
let unique_ids: HashSet<String> = ids_itarator.collect();
|
||||
let mut ids: Vec<String> = unique_ids.into_iter().collect();
|
||||
let mut ids: Vec<BranchId> = unique_ids
|
||||
.into_iter()
|
||||
.map(|id| id.parse())
|
||||
.filter_map(Result::ok)
|
||||
.collect();
|
||||
ids.sort();
|
||||
Ok(Self {
|
||||
branch_reader: branch::Reader::new(reader),
|
||||
@ -72,9 +76,9 @@ mod tests {
|
||||
TEST_INDEX.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
branch::Branch {
|
||||
id: format!("branch_{}", TEST_INDEX.load(Ordering::Relaxed)),
|
||||
id: BranchId::generate(),
|
||||
name: format!("branch_name_{}", TEST_INDEX.load(Ordering::Relaxed)),
|
||||
notes: "".to_string(),
|
||||
notes: String::new(),
|
||||
applied: true,
|
||||
upstream: Some(
|
||||
format!(
|
||||
@ -157,10 +161,12 @@ mod tests {
|
||||
let session = gb_repository.get_current_session()?.unwrap();
|
||||
let session_reader = sessions::Reader::open(&gb_repository, &session)?;
|
||||
|
||||
let mut iter = BranchIterator::new(&session_reader)?;
|
||||
assert_eq!(iter.next().unwrap().unwrap(), branch_1);
|
||||
assert_eq!(iter.next().unwrap().unwrap(), branch_2);
|
||||
assert_eq!(iter.next().unwrap().unwrap(), branch_3);
|
||||
let iter =
|
||||
BranchIterator::new(&session_reader)?.collect::<Result<Vec<_>, reader::Error>>()?;
|
||||
assert_eq!(iter.len(), 3);
|
||||
assert!(iter.contains(&branch_1));
|
||||
assert!(iter.contains(&branch_2));
|
||||
assert!(iter.contains(&branch_3));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
pub mod branch;
|
||||
pub use branch::Branch;
|
||||
pub use branch::{Branch, BranchId};
|
||||
pub mod target;
|
||||
|
||||
mod files;
|
||||
|
@ -1,6 +1,9 @@
|
||||
use std::path;
|
||||
|
||||
use crate::reader::{self, SubReader};
|
||||
use crate::{
|
||||
reader::{self, SubReader},
|
||||
virtual_branches::BranchId,
|
||||
};
|
||||
|
||||
use super::Target;
|
||||
|
||||
@ -22,7 +25,7 @@ impl<'reader> TargetReader<'reader> {
|
||||
Target::try_from(reader)
|
||||
}
|
||||
|
||||
pub fn read(&self, id: &str) -> Result<Target, reader::Error> {
|
||||
pub fn read(&self, id: &BranchId) -> Result<Target, reader::Error> {
|
||||
if !self
|
||||
.reader
|
||||
.exists(&path::PathBuf::from(format!("branches/{}/target", id)))
|
||||
@ -58,7 +61,7 @@ mod tests {
|
||||
TEST_INDEX.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
branch::Branch {
|
||||
id: format!("branch_{}", TEST_INDEX.load(Ordering::Relaxed)),
|
||||
id: BranchId::generate(),
|
||||
name: format!("branch_name_{}", TEST_INDEX.load(Ordering::Relaxed)),
|
||||
notes: "".to_string(),
|
||||
applied: true,
|
||||
@ -103,7 +106,7 @@ mod tests {
|
||||
let session_reader = sessions::Reader::open(&gb_repository, &session)?;
|
||||
|
||||
let reader = TargetReader::new(&session_reader);
|
||||
let result = reader.read("not found");
|
||||
let result = reader.read(&BranchId::generate());
|
||||
assert!(result.is_err());
|
||||
assert_eq!(result.unwrap_err().to_string(), "file not found");
|
||||
|
||||
|
@ -2,6 +2,7 @@ use anyhow::{Context, Result};
|
||||
|
||||
use crate::{
|
||||
gb_repository,
|
||||
virtual_branches::BranchId,
|
||||
writer::{self, Writer},
|
||||
};
|
||||
|
||||
@ -43,7 +44,7 @@ impl<'writer> TargetWriter<'writer> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write(&self, id: &str, target: &Target) -> Result<()> {
|
||||
pub fn write(&self, id: &BranchId, target: &Target) -> Result<()> {
|
||||
self.repository
|
||||
.mark_active_session()
|
||||
.context("Failed to get or create current session")?;
|
||||
@ -101,7 +102,7 @@ mod tests {
|
||||
TEST_INDEX.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
branch::Branch {
|
||||
id: format!("branch_{}", TEST_INDEX.load(Ordering::Relaxed)),
|
||||
id: BranchId::generate(),
|
||||
name: format!("branch_name_{}", TEST_INDEX.load(Ordering::Relaxed)),
|
||||
notes: format!("branch_notes_{}", TEST_INDEX.load(Ordering::Relaxed)),
|
||||
applied: true,
|
||||
@ -155,7 +156,10 @@ mod tests {
|
||||
let target_writer = TargetWriter::new(&gb_repository);
|
||||
target_writer.write(&branch.id, &target)?;
|
||||
|
||||
let root = gb_repository.root().join("branches").join(&branch.id);
|
||||
let root = gb_repository
|
||||
.root()
|
||||
.join("branches")
|
||||
.join(branch.id.to_string());
|
||||
|
||||
assert_eq!(
|
||||
fs::read_to_string(root.join("meta").join("name").to_str().unwrap())
|
||||
@ -247,7 +251,10 @@ mod tests {
|
||||
|
||||
target_writer.write(&branch.id, &updated_target)?;
|
||||
|
||||
let root = gb_repository.root().join("branches").join(&branch.id);
|
||||
let root = gb_repository
|
||||
.root()
|
||||
.join("branches")
|
||||
.join(branch.id.to_string());
|
||||
|
||||
assert_eq!(
|
||||
fs::read_to_string(root.join("target").join("branch_name").to_str().unwrap())
|
||||
|
@ -8,8 +8,6 @@ use anyhow::{anyhow, bail, Context, Result};
|
||||
use diffy::{apply_bytes, Patch};
|
||||
use serde::Serialize;
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
dedup::{dedup, dedup_fmt},
|
||||
gb_repository,
|
||||
@ -20,7 +18,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
branch::{self, Branch, BranchCreateRequest, FileOwnership, Hunk, Ownership},
|
||||
branch::{self, Branch, BranchCreateRequest, BranchId, FileOwnership, Hunk, Ownership},
|
||||
target, Iterator,
|
||||
};
|
||||
|
||||
@ -35,7 +33,7 @@ use super::{
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
pub struct VirtualBranch {
|
||||
pub id: String,
|
||||
pub id: BranchId,
|
||||
pub name: String,
|
||||
pub notes: String,
|
||||
pub active: bool,
|
||||
@ -152,7 +150,7 @@ pub fn get_default_target(
|
||||
pub fn apply_branch(
|
||||
gb_repository: &gb_repository::Repository,
|
||||
project_repository: &project_repository::Repository,
|
||||
branch_id: &str,
|
||||
branch_id: &BranchId,
|
||||
signing_key: Option<&keys::PrivateKey>,
|
||||
user: Option<&users::User>,
|
||||
) -> Result<()> {
|
||||
@ -411,7 +409,7 @@ pub fn unapply_ownership(
|
||||
pub fn unapply_branch(
|
||||
gb_repository: &gb_repository::Repository,
|
||||
project_repository: &project_repository::Repository,
|
||||
branch_id: &str,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<()> {
|
||||
if conflicts::is_resolving(project_repository) {
|
||||
bail!("cannot unapply, project is in a conflicted state");
|
||||
@ -458,7 +456,7 @@ pub fn unapply_branch(
|
||||
|
||||
let status = applied_statuses
|
||||
.iter()
|
||||
.find(|(s, _)| s.id == branch_id)
|
||||
.find(|(s, _)| s.id == *branch_id)
|
||||
.context("failed to find status for branch");
|
||||
|
||||
let repo = &project_repository.git_repository;
|
||||
@ -482,7 +480,7 @@ pub fn unapply_branch(
|
||||
// then check that out into the working directory
|
||||
let final_tree = applied_statuses
|
||||
.into_iter()
|
||||
.filter(|(branch, _)| branch.id != branch_id)
|
||||
.filter(|(branch, _)| branch.id != *branch_id)
|
||||
.fold(
|
||||
target_commit.tree().context("failed to get target tree"),
|
||||
|final_tree, status| {
|
||||
@ -642,7 +640,7 @@ pub fn list_virtual_branches(
|
||||
let requires_force = is_requires_force(project_repository, branch)?;
|
||||
|
||||
let branch = VirtualBranch {
|
||||
id: branch.id.clone(),
|
||||
id: branch.id,
|
||||
name: branch.name.clone(),
|
||||
notes: branch.notes.clone(),
|
||||
active: branch.applied,
|
||||
@ -937,7 +935,7 @@ pub fn create_virtual_branch(
|
||||
);
|
||||
|
||||
let mut branch = Branch {
|
||||
id: Uuid::new_v4().to_string(),
|
||||
id: BranchId::generate(),
|
||||
name,
|
||||
notes: String::new(),
|
||||
applied: true,
|
||||
@ -967,7 +965,7 @@ pub fn create_virtual_branch(
|
||||
pub fn merge_virtual_branch_upstream(
|
||||
gb_repository: &gb_repository::Repository,
|
||||
project_repository: &project_repository::Repository,
|
||||
branch_id: &str,
|
||||
branch_id: &BranchId,
|
||||
signing_key: Option<&keys::PrivateKey>,
|
||||
user: Option<&users::User>,
|
||||
) -> Result<()> {
|
||||
@ -1023,7 +1021,7 @@ pub fn merge_virtual_branch_upstream(
|
||||
.context("failed to read virtual branches")?
|
||||
.into_iter()
|
||||
.filter(|b| b.applied)
|
||||
.filter(|b| b.id != branch_id)
|
||||
.filter(|b| b.id != *branch_id)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// unapply all other branches
|
||||
@ -1201,7 +1199,7 @@ pub fn update_branch(
|
||||
pub fn delete_branch(
|
||||
gb_repository: &gb_repository::Repository,
|
||||
project_repository: &project_repository::Repository,
|
||||
branch_id: &str,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<branch::Branch> {
|
||||
let current_session = gb_repository
|
||||
.get_or_create_current_session()
|
||||
@ -1491,9 +1489,9 @@ fn get_applied_status(
|
||||
// - update shifted hunks
|
||||
// - remove non existent hunks
|
||||
|
||||
let mut hunks_by_branch_id: HashMap<String, Vec<VirtualBranchHunk>> = virtual_branches
|
||||
let mut hunks_by_branch_id: HashMap<BranchId, Vec<VirtualBranchHunk>> = virtual_branches
|
||||
.iter()
|
||||
.map(|branch| (branch.id.clone(), vec![]))
|
||||
.map(|branch| (branch.id, vec![]))
|
||||
.collect();
|
||||
|
||||
for branch in &mut virtual_branches {
|
||||
@ -1680,7 +1678,7 @@ fn virtual_hunks_to_virtual_files(
|
||||
pub fn reset_branch(
|
||||
gb_repository: &gb_repository::Repository,
|
||||
project_repository: &project_repository::Repository,
|
||||
branch_id: &str,
|
||||
branch_id: &BranchId,
|
||||
target_commit_oid: git::Oid,
|
||||
) -> Result<()> {
|
||||
let current_session = gb_repository.get_or_create_current_session()?;
|
||||
@ -1884,7 +1882,7 @@ fn _print_tree(repo: &git2::Repository, tree: &git2::Tree) -> Result<()> {
|
||||
pub fn commit(
|
||||
gb_repository: &gb_repository::Repository,
|
||||
project_repository: &project_repository::Repository,
|
||||
branch_id: &str,
|
||||
branch_id: &BranchId,
|
||||
message: &str,
|
||||
ownership: Option<&branch::Ownership>,
|
||||
signing_key: Option<&keys::PrivateKey>,
|
||||
@ -1901,7 +1899,7 @@ pub fn commit(
|
||||
|
||||
let (branch, files) = statuses
|
||||
.iter()
|
||||
.find(|(branch, _)| branch.id == branch_id)
|
||||
.find(|(branch, _)| branch.id == *branch_id)
|
||||
.ok_or_else(|| anyhow!("branch {} not found", branch_id))?;
|
||||
|
||||
let files = calculate_non_commited_files(project_repository, branch, &default_target, files)?;
|
||||
@ -2033,7 +2031,7 @@ pub enum PushError {
|
||||
pub fn push(
|
||||
project_repository: &project_repository::Repository,
|
||||
gb_repository: &gb_repository::Repository,
|
||||
branch_id: &str,
|
||||
branch_id: &BranchId,
|
||||
with_force: bool,
|
||||
key: &Key,
|
||||
) -> Result<(), PushError> {
|
||||
@ -2220,7 +2218,7 @@ pub fn is_remote_branch_mergeable(
|
||||
pub fn is_virtual_branch_mergeable(
|
||||
gb_repository: &gb_repository::Repository,
|
||||
project_repository: &project_repository::Repository,
|
||||
branch_id: &str,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<bool> {
|
||||
let current_session = gb_repository
|
||||
.get_or_create_current_session()
|
||||
|
@ -198,6 +198,8 @@ mod test {
|
||||
virtual_branches::{self, branch},
|
||||
};
|
||||
|
||||
use self::branch::BranchId;
|
||||
|
||||
use super::*;
|
||||
|
||||
static TEST_TARGET_INDEX: Lazy<AtomicUsize> = Lazy::new(|| AtomicUsize::new(0));
|
||||
@ -227,7 +229,7 @@ mod test {
|
||||
TEST_INDEX.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
virtual_branches::branch::Branch {
|
||||
id: format!("branch_{}", TEST_INDEX.load(Ordering::Relaxed)),
|
||||
id: BranchId::generate(),
|
||||
name: format!("branch_name_{}", TEST_INDEX.load(Ordering::Relaxed)),
|
||||
notes: format!("branch_notes_{}", TEST_INDEX.load(Ordering::Relaxed)),
|
||||
applied: true,
|
||||
@ -519,7 +521,7 @@ mod test {
|
||||
// get all the created sessions
|
||||
let mut sessions: Vec<sessions::Session> = gb_repository
|
||||
.get_sessions_iterator()?
|
||||
.map(|s| s.unwrap())
|
||||
.map(Result::unwrap)
|
||||
.collect();
|
||||
assert_eq!(sessions.len(), size);
|
||||
// verify sessions order is correct
|
||||
@ -534,23 +536,23 @@ mod test {
|
||||
|
||||
sessions.reverse();
|
||||
// try to reconstruct file state from operations for every session slice
|
||||
for i in 0..=sessions.len() - 1 {
|
||||
for i in 0..sessions.len() {
|
||||
let sessions_slice = &mut sessions[i..];
|
||||
|
||||
// collect all operations from sessions in the reverse order
|
||||
let mut operations: Vec<deltas::Operation> = vec![];
|
||||
sessions_slice.iter().for_each(|session| {
|
||||
for session in &mut *sessions_slice {
|
||||
let session_reader = sessions::Reader::open(&gb_repository, session).unwrap();
|
||||
let deltas_reader = deltas::Reader::new(&session_reader);
|
||||
let deltas_by_filepath = deltas_reader.read(&None).unwrap();
|
||||
for deltas in deltas_by_filepath.values() {
|
||||
deltas.iter().for_each(|delta| {
|
||||
for delta in deltas {
|
||||
delta.operations.iter().for_each(|operation| {
|
||||
operations.push(operation.clone());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let reader =
|
||||
sessions::Reader::open(&gb_repository, sessions_slice.first().unwrap()).unwrap();
|
||||
@ -605,7 +607,7 @@ mod test {
|
||||
// get all the created sessions
|
||||
let mut sessions: Vec<sessions::Session> = gb_repository
|
||||
.get_sessions_iterator()?
|
||||
.map(|s| s.unwrap())
|
||||
.map(Result::unwrap)
|
||||
.collect();
|
||||
assert_eq!(sessions.len(), size);
|
||||
// verify sessions order is correct
|
||||
@ -620,23 +622,23 @@ mod test {
|
||||
|
||||
sessions.reverse();
|
||||
// try to reconstruct file state from operations for every session slice
|
||||
for i in 0..=sessions.len() - 1 {
|
||||
for i in 0..sessions.len() {
|
||||
let sessions_slice = &mut sessions[i..];
|
||||
|
||||
// collect all operations from sessions in the reverse order
|
||||
let mut operations: Vec<deltas::Operation> = vec![];
|
||||
sessions_slice.iter().for_each(|session| {
|
||||
for session in &mut *sessions_slice {
|
||||
let session_reader = sessions::Reader::open(&gb_repository, session).unwrap();
|
||||
let deltas_reader = deltas::Reader::new(&session_reader);
|
||||
let deltas_by_filepath = deltas_reader.read(&None).unwrap();
|
||||
for deltas in deltas_by_filepath.values() {
|
||||
deltas.iter().for_each(|delta| {
|
||||
for delta in deltas {
|
||||
delta.operations.iter().for_each(|operation| {
|
||||
operations.push(operation.clone());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let reader =
|
||||
sessions::Reader::open(&gb_repository, sessions_slice.first().unwrap()).unwrap();
|
||||
@ -673,9 +675,9 @@ mod test {
|
||||
} = suite.new_case();
|
||||
let listener = Handler::from(&suite.local_app_data);
|
||||
|
||||
let size = 10;
|
||||
let size = 10_i32;
|
||||
let relative_file_path = std::path::Path::new("one/two/test.txt");
|
||||
for i in 1..=size {
|
||||
for i in 1_i32..=size {
|
||||
std::fs::create_dir_all(std::path::Path::new(&project.path).join("one/two"))?;
|
||||
// create a session with a single file change and flush it
|
||||
std::fs::write(
|
||||
@ -693,11 +695,11 @@ mod test {
|
||||
let deltas_reader = deltas::Reader::new(&session_reader);
|
||||
let deltas_by_filepath = deltas_reader.read(&None).unwrap();
|
||||
for deltas in deltas_by_filepath.values() {
|
||||
deltas.iter().for_each(|delta| {
|
||||
for delta in deltas {
|
||||
delta.operations.iter().for_each(|operation| {
|
||||
operations.push(operation.clone());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let reader = sessions::Reader::open(&gb_repository, &session).unwrap();
|
||||
|
Loading…
Reference in New Issue
Block a user