store: rename Store to Backend and StoreWrapper to Store

For what's currently called `Store` in the code, I have been using
"backend" in plain text. That probably means that `Backend` is a good
name for it.
This commit is contained in:
Martin von Zweigbergk 2021-09-11 23:52:38 -07:00
parent 1f2ce49e89
commit ce5e95fa80
48 changed files with 932 additions and 958 deletions

318
lib/src/backend.rs Normal file
View file

@ -0,0 +1,318 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::collections::BTreeMap;
use std::fmt::{Debug, Error, Formatter};
use std::io::Read;
use std::result::Result;
use std::vec::Vec;
use thiserror::Error;
use crate::repo_path::{RepoPath, RepoPathComponent};
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct CommitId(pub Vec<u8>);
impl Debug for CommitId {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_tuple("CommitId").field(&self.hex()).finish()
}
}
impl CommitId {
pub fn from_hex(hex: &str) -> Self {
CommitId(hex::decode(hex).unwrap())
}
pub fn hex(&self) -> String {
hex::encode(&self.0)
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct ChangeId(pub Vec<u8>);
impl Debug for ChangeId {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_tuple("ChangeId").field(&self.hex()).finish()
}
}
impl ChangeId {
pub fn from_hex(hex: &str) -> Self {
ChangeId(hex::decode(hex).unwrap())
}
pub fn hex(&self) -> String {
hex::encode(&self.0)
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct TreeId(pub Vec<u8>);
impl Debug for TreeId {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_tuple("TreeId").field(&self.hex()).finish()
}
}
impl TreeId {
pub fn hex(&self) -> String {
hex::encode(&self.0)
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct FileId(pub Vec<u8>);
impl Debug for FileId {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_tuple("FileId").field(&self.hex()).finish()
}
}
impl FileId {
pub fn hex(&self) -> String {
hex::encode(&self.0)
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct SymlinkId(pub Vec<u8>);
impl Debug for SymlinkId {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_tuple("SymlinkId").field(&self.hex()).finish()
}
}
impl SymlinkId {
pub fn hex(&self) -> String {
hex::encode(&self.0)
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct ConflictId(pub Vec<u8>);
impl Debug for ConflictId {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_tuple("ConflictId").field(&self.hex()).finish()
}
}
impl ConflictId {
pub fn hex(&self) -> String {
hex::encode(&self.0)
}
}
pub enum Phase {
Public,
Draft,
}
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord)]
pub struct MillisSinceEpoch(pub u64);
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord)]
pub struct Timestamp {
pub timestamp: MillisSinceEpoch,
// time zone offset in minutes
pub tz_offset: i32,
}
impl Timestamp {
pub fn now() -> Self {
let now = chrono::offset::Local::now();
Self {
timestamp: MillisSinceEpoch(now.timestamp_millis() as u64),
tz_offset: now.offset().local_minus_utc() / 60,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Signature {
pub name: String,
pub email: String,
pub timestamp: Timestamp,
}
#[derive(Debug, Clone)]
pub struct Commit {
pub parents: Vec<CommitId>,
pub predecessors: Vec<CommitId>,
pub root_tree: TreeId,
pub change_id: ChangeId,
pub description: String,
pub author: Signature,
pub committer: Signature,
pub is_open: bool,
pub is_pruned: bool,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ConflictPart {
// TODO: Store e.g. CommitId here too? Labels (theirs/ours/base)? Would those still be
// useful e.g. after rebasing this conflict?
pub value: TreeValue,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Conflict {
// A conflict is represented by a list of positive and negative states that need to be applied.
// In a simple 3-way merge of B and C with merge base A, the conflict will be { add: [B, C],
// remove: [A] }. Also note that a conflict of the form { add: [A], remove: [] } is the
// same as non-conflict A.
pub removes: Vec<ConflictPart>,
pub adds: Vec<ConflictPart>,
}
impl Default for Conflict {
fn default() -> Self {
Conflict {
removes: Default::default(),
adds: Default::default(),
}
}
}
#[derive(Debug, Error, PartialEq, Eq)]
pub enum BackendError {
#[error("Object not found")]
NotFound,
#[error("Error: {0}")]
Other(String),
}
pub type BackendResult<T> = Result<T, BackendError>;
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum TreeValue {
Normal { id: FileId, executable: bool },
Symlink(SymlinkId),
Tree(TreeId),
GitSubmodule(CommitId),
Conflict(ConflictId),
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct TreeEntry<'a> {
name: &'a RepoPathComponent,
value: &'a TreeValue,
}
impl<'a> TreeEntry<'a> {
pub fn new(name: &'a RepoPathComponent, value: &'a TreeValue) -> Self {
TreeEntry { name, value }
}
pub fn name(&self) -> &'a RepoPathComponent {
self.name
}
pub fn value(&self) -> &'a TreeValue {
self.value
}
}
pub struct TreeEntriesNonRecursiveIter<'a> {
iter: std::collections::btree_map::Iter<'a, RepoPathComponent, TreeValue>,
}
impl<'a> Iterator for TreeEntriesNonRecursiveIter<'a> {
type Item = TreeEntry<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(|(name, value)| TreeEntry { name, value })
}
}
#[derive(Debug, Clone)]
pub struct Tree {
entries: BTreeMap<RepoPathComponent, TreeValue>,
}
impl Default for Tree {
fn default() -> Self {
Self {
entries: BTreeMap::new(),
}
}
}
impl Tree {
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn entries(&self) -> TreeEntriesNonRecursiveIter {
TreeEntriesNonRecursiveIter {
iter: self.entries.iter(),
}
}
pub fn set(&mut self, name: RepoPathComponent, value: TreeValue) {
self.entries.insert(name, value);
}
pub fn remove(&mut self, name: &RepoPathComponent) {
self.entries.remove(name);
}
pub fn entry(&self, name: &RepoPathComponent) -> Option<TreeEntry> {
self.entries
.get_key_value(name)
.map(|(name, value)| TreeEntry { name, value })
}
pub fn value(&self, name: &RepoPathComponent) -> Option<&TreeValue> {
self.entries.get(name)
}
}
pub trait Backend: Send + Sync + Debug {
fn hash_length(&self) -> usize;
fn git_repo(&self) -> Option<git2::Repository>;
fn read_file(&self, path: &RepoPath, id: &FileId) -> BackendResult<Box<dyn Read>>;
fn write_file(&self, path: &RepoPath, contents: &mut dyn Read) -> BackendResult<FileId>;
fn read_symlink(&self, path: &RepoPath, id: &SymlinkId) -> BackendResult<String>;
fn write_symlink(&self, path: &RepoPath, target: &str) -> BackendResult<SymlinkId>;
fn empty_tree_id(&self) -> &TreeId;
fn read_tree(&self, path: &RepoPath, id: &TreeId) -> BackendResult<Tree>;
fn write_tree(&self, path: &RepoPath, contents: &Tree) -> BackendResult<TreeId>;
fn read_commit(&self, id: &CommitId) -> BackendResult<Commit>;
fn write_commit(&self, contents: &Commit) -> BackendResult<CommitId>;
// TODO: Pass in the paths here too even though they are unused, just like for
// files and trees?
fn read_conflict(&self, id: &ConflictId) -> BackendResult<Conflict>;
fn write_conflict(&self, contents: &Conflict) -> BackendResult<ConflictId>;
}

View file

@ -17,17 +17,17 @@ use std::fmt::{Debug, Error, Formatter};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::sync::Arc; use std::sync::Arc;
use crate::backend;
use crate::backend::{ChangeId, CommitId, Signature};
use crate::repo_path::RepoPath; use crate::repo_path::RepoPath;
use crate::store; use crate::store::Store;
use crate::store::{ChangeId, CommitId, Signature};
use crate::store_wrapper::StoreWrapper;
use crate::tree::Tree; use crate::tree::Tree;
#[derive(Clone)] #[derive(Clone)]
pub struct Commit { pub struct Commit {
store: Arc<StoreWrapper>, store: Arc<Store>,
id: CommitId, id: CommitId,
data: Arc<store::Commit>, data: Arc<backend::Commit>,
} }
impl Debug for Commit { impl Debug for Commit {
@ -63,11 +63,11 @@ impl Hash for Commit {
} }
impl Commit { impl Commit {
pub fn new(store: Arc<StoreWrapper>, id: CommitId, data: Arc<store::Commit>) -> Self { pub fn new(store: Arc<Store>, id: CommitId, data: Arc<backend::Commit>) -> Self {
Commit { store, id, data } Commit { store, id, data }
} }
pub fn store(&self) -> &Arc<StoreWrapper> { pub fn store(&self) -> &Arc<Store> {
&self.store &self.store
} }
@ -116,7 +116,7 @@ impl Commit {
&self.data.change_id &self.data.change_id
} }
pub fn store_commit(&self) -> &store::Commit { pub fn store_commit(&self) -> &backend::Commit {
&self.data &self.data
} }

View file

@ -16,17 +16,17 @@ use std::sync::Arc;
use uuid::Uuid; use uuid::Uuid;
use crate::backend;
use crate::backend::{ChangeId, CommitId, Signature, Timestamp, TreeId};
use crate::commit::Commit; use crate::commit::Commit;
use crate::repo::MutableRepo; use crate::repo::MutableRepo;
use crate::settings::UserSettings; use crate::settings::UserSettings;
use crate::store; use crate::store::Store;
use crate::store::{ChangeId, CommitId, Signature, Timestamp, TreeId};
use crate::store_wrapper::StoreWrapper;
#[derive(Debug)] #[derive(Debug)]
pub struct CommitBuilder { pub struct CommitBuilder {
store: Arc<StoreWrapper>, store: Arc<Store>,
commit: store::Commit, commit: backend::Commit,
} }
pub fn new_change_id() -> ChangeId { pub fn new_change_id() -> ChangeId {
@ -45,11 +45,11 @@ pub fn signature(settings: &UserSettings) -> Signature {
impl CommitBuilder { impl CommitBuilder {
pub fn for_new_commit( pub fn for_new_commit(
settings: &UserSettings, settings: &UserSettings,
store: &Arc<StoreWrapper>, store: &Arc<Store>,
tree_id: TreeId, tree_id: TreeId,
) -> CommitBuilder { ) -> CommitBuilder {
let signature = signature(settings); let signature = signature(settings);
let commit = store::Commit { let commit = backend::Commit {
parents: vec![], parents: vec![],
predecessors: vec![], predecessors: vec![],
root_tree: tree_id, root_tree: tree_id,
@ -68,7 +68,7 @@ impl CommitBuilder {
pub fn for_rewrite_from( pub fn for_rewrite_from(
settings: &UserSettings, settings: &UserSettings,
store: &Arc<StoreWrapper>, store: &Arc<Store>,
predecessor: &Commit, predecessor: &Commit,
) -> CommitBuilder { ) -> CommitBuilder {
let mut commit = predecessor.store_commit().clone(); let mut commit = predecessor.store_commit().clone();
@ -82,12 +82,12 @@ impl CommitBuilder {
pub fn for_open_commit( pub fn for_open_commit(
settings: &UserSettings, settings: &UserSettings,
store: &Arc<StoreWrapper>, store: &Arc<Store>,
parent_id: CommitId, parent_id: CommitId,
tree_id: TreeId, tree_id: TreeId,
) -> CommitBuilder { ) -> CommitBuilder {
let signature = signature(settings); let signature = signature(settings);
let commit = store::Commit { let commit = backend::Commit {
parents: vec![parent_id], parents: vec![parent_id],
predecessors: vec![], predecessors: vec![],
root_tree: tree_id, root_tree: tree_id,

View file

@ -17,12 +17,12 @@ use std::io::{Cursor, Write};
use itertools::Itertools; use itertools::Itertools;
use crate::backend::{Conflict, ConflictPart, TreeValue};
use crate::diff::{find_line_ranges, Diff, DiffHunk}; use crate::diff::{find_line_ranges, Diff, DiffHunk};
use crate::files; use crate::files;
use crate::files::{MergeHunk, MergeResult}; use crate::files::{MergeHunk, MergeResult};
use crate::repo_path::RepoPath; use crate::repo_path::RepoPath;
use crate::store::{Conflict, ConflictPart, TreeValue}; use crate::store::Store;
use crate::store_wrapper::StoreWrapper;
fn describe_conflict_part(part: &ConflictPart) -> String { fn describe_conflict_part(part: &ConflictPart) -> String {
match &part.value { match &part.value {
@ -79,7 +79,7 @@ fn file_parts(parts: &[ConflictPart]) -> Vec<&ConflictPart> {
.collect_vec() .collect_vec()
} }
fn get_file_contents(store: &StoreWrapper, path: &RepoPath, part: &ConflictPart) -> Vec<u8> { fn get_file_contents(store: &Store, path: &RepoPath, part: &ConflictPart) -> Vec<u8> {
if let TreeValue::Normal { if let TreeValue::Normal {
id, id,
executable: false, executable: false,
@ -123,7 +123,7 @@ fn write_diff_hunks(left: &[u8], right: &[u8], file: &mut dyn Write) -> std::io:
} }
pub fn materialize_conflict( pub fn materialize_conflict(
store: &StoreWrapper, store: &Store,
path: &RepoPath, path: &RepoPath,
conflict: &Conflict, conflict: &Conflict,
file: &mut dyn Write, file: &mut dyn Write,
@ -190,7 +190,7 @@ pub fn materialize_conflict(
} }
pub fn conflict_to_materialized_value( pub fn conflict_to_materialized_value(
store: &StoreWrapper, store: &Store,
path: &RepoPath, path: &RepoPath,
conflict: &Conflict, conflict: &Conflict,
) -> TreeValue { ) -> TreeValue {

View file

@ -17,6 +17,7 @@ use std::sync::Arc;
use itertools::Itertools; use itertools::Itertools;
use crate::backend::{ChangeId, CommitId};
use crate::commit::Commit; use crate::commit::Commit;
use crate::commit_builder::CommitBuilder; use crate::commit_builder::CommitBuilder;
use crate::dag_walk::{bfs, closest_common_node, leaves}; use crate::dag_walk::{bfs, closest_common_node, leaves};
@ -25,8 +26,7 @@ use crate::repo::{MutableRepo, ReadonlyRepo, RepoRef};
use crate::repo_path::RepoPath; use crate::repo_path::RepoPath;
use crate::rewrite::{merge_commit_trees, rebase_commit}; use crate::rewrite::{merge_commit_trees, rebase_commit};
use crate::settings::UserSettings; use crate::settings::UserSettings;
use crate::store::{ChangeId, CommitId}; use crate::store::Store;
use crate::store_wrapper::StoreWrapper;
use crate::tree::merge_trees; use crate::tree::merge_trees;
// TODO: Combine some maps/sets and use a struct as value instead. // TODO: Combine some maps/sets and use a struct as value instead.
@ -608,7 +608,7 @@ pub enum OrphanResolution {
fn evolve_divergent_change( fn evolve_divergent_change(
user_settings: &UserSettings, user_settings: &UserSettings,
store: &Arc<StoreWrapper>, store: &Arc<Store>,
mut_repo: &mut MutableRepo, mut_repo: &mut MutableRepo,
commits: &HashSet<Commit>, commits: &HashSet<Commit>,
) -> DivergenceResolution { ) -> DivergenceResolution {
@ -657,7 +657,7 @@ fn evolve_divergent_change(
fn evolve_two_divergent_commits( fn evolve_two_divergent_commits(
user_settings: &UserSettings, user_settings: &UserSettings,
store: &Arc<StoreWrapper>, store: &Arc<Store>,
mut_repo: &mut MutableRepo, mut_repo: &mut MutableRepo,
common_predecessor: &Commit, common_predecessor: &Commit,
commit1: &Commit, commit1: &Commit,

View file

@ -18,10 +18,10 @@ use git2::FetchPrune;
use itertools::Itertools; use itertools::Itertools;
use thiserror::Error; use thiserror::Error;
use crate::backend::CommitId;
use crate::commit::Commit; use crate::commit::Commit;
use crate::op_store::RefTarget; use crate::op_store::RefTarget;
use crate::repo::MutableRepo; use crate::repo::MutableRepo;
use crate::store::CommitId;
use crate::view::RefName; use crate::view::RefName;
#[derive(Error, Debug, PartialEq)] #[derive(Error, Debug, PartialEq)]

View file

@ -25,11 +25,12 @@ use itertools::Itertools;
use protobuf::Message; use protobuf::Message;
use uuid::Uuid; use uuid::Uuid;
use crate::repo_path::{RepoPath, RepoPathComponent}; use crate::backend::{
use crate::store::{ Backend, BackendError, BackendResult, ChangeId, Commit, CommitId, Conflict, ConflictId,
ChangeId, Commit, CommitId, Conflict, ConflictId, ConflictPart, FileId, MillisSinceEpoch, ConflictPart, FileId, MillisSinceEpoch, Signature, SymlinkId, Timestamp, Tree, TreeId,
Signature, Store, StoreError, StoreResult, SymlinkId, Timestamp, Tree, TreeId, TreeValue, TreeValue,
}; };
use crate::repo_path::{RepoPath, RepoPathComponent};
/// Ref namespace used only for preventing GC. /// Ref namespace used only for preventing GC.
const NO_GC_REF_NAMESPACE: &str = "refs/jj/keep/"; const NO_GC_REF_NAMESPACE: &str = "refs/jj/keep/";
@ -37,26 +38,26 @@ const NO_GC_REF_NAMESPACE: &str = "refs/jj/keep/";
const COMMITS_NOTES_REF: &str = "refs/notes/jj/commits"; const COMMITS_NOTES_REF: &str = "refs/notes/jj/commits";
const CONFLICT_SUFFIX: &str = ".jjconflict"; const CONFLICT_SUFFIX: &str = ".jjconflict";
impl From<git2::Error> for StoreError { impl From<git2::Error> for BackendError {
fn from(err: git2::Error) -> Self { fn from(err: git2::Error) -> Self {
match err.code() { match err.code() {
git2::ErrorCode::NotFound => StoreError::NotFound, git2::ErrorCode::NotFound => BackendError::NotFound,
_other => StoreError::Other(err.to_string()), _other => BackendError::Other(err.to_string()),
} }
} }
} }
pub struct GitStore { pub struct GitBackend {
repo: Mutex<git2::Repository>, repo: Mutex<git2::Repository>,
empty_tree_id: TreeId, empty_tree_id: TreeId,
} }
impl GitStore { impl GitBackend {
pub fn load(path: &Path) -> Self { pub fn load(path: &Path) -> Self {
let repo = Mutex::new(git2::Repository::open(path).unwrap()); let repo = Mutex::new(git2::Repository::open(path).unwrap());
let empty_tree_id = let empty_tree_id =
TreeId(hex::decode("4b825dc642cb6eb9a060e54bf8d69288fbee4904").unwrap()); TreeId(hex::decode("4b825dc642cb6eb9a060e54bf8d69288fbee4904").unwrap());
GitStore { GitBackend {
repo, repo,
empty_tree_id, empty_tree_id,
} }
@ -159,7 +160,7 @@ fn write_note(
Ok(()) Ok(())
} }
impl Debug for GitStore { impl Debug for GitBackend {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_struct("GitStore") f.debug_struct("GitStore")
.field("path", &self.repo.lock().unwrap().path()) .field("path", &self.repo.lock().unwrap().path())
@ -167,7 +168,7 @@ impl Debug for GitStore {
} }
} }
impl Store for GitStore { impl Backend for GitBackend {
fn hash_length(&self) -> usize { fn hash_length(&self) -> usize {
20 20
} }
@ -177,9 +178,9 @@ impl Store for GitStore {
Some(git2::Repository::open(&path).unwrap()) Some(git2::Repository::open(&path).unwrap())
} }
fn read_file(&self, _path: &RepoPath, id: &FileId) -> StoreResult<Box<dyn Read>> { fn read_file(&self, _path: &RepoPath, id: &FileId) -> BackendResult<Box<dyn Read>> {
if id.0.len() != self.hash_length() { if id.0.len() != self.hash_length() {
return Err(StoreError::NotFound); return Err(BackendError::NotFound);
} }
let locked_repo = self.repo.lock().unwrap(); let locked_repo = self.repo.lock().unwrap();
let blob = locked_repo let blob = locked_repo
@ -189,7 +190,7 @@ impl Store for GitStore {
Ok(Box::new(Cursor::new(content))) Ok(Box::new(Cursor::new(content)))
} }
fn write_file(&self, _path: &RepoPath, contents: &mut dyn Read) -> StoreResult<FileId> { fn write_file(&self, _path: &RepoPath, contents: &mut dyn Read) -> BackendResult<FileId> {
let mut bytes = Vec::new(); let mut bytes = Vec::new();
contents.read_to_end(&mut bytes).unwrap(); contents.read_to_end(&mut bytes).unwrap();
let locked_repo = self.repo.lock().unwrap(); let locked_repo = self.repo.lock().unwrap();
@ -197,9 +198,9 @@ impl Store for GitStore {
Ok(FileId(oid.as_bytes().to_vec())) Ok(FileId(oid.as_bytes().to_vec()))
} }
fn read_symlink(&self, _path: &RepoPath, id: &SymlinkId) -> Result<String, StoreError> { fn read_symlink(&self, _path: &RepoPath, id: &SymlinkId) -> Result<String, BackendError> {
if id.0.len() != self.hash_length() { if id.0.len() != self.hash_length() {
return Err(StoreError::NotFound); return Err(BackendError::NotFound);
} }
let locked_repo = self.repo.lock().unwrap(); let locked_repo = self.repo.lock().unwrap();
let blob = locked_repo let blob = locked_repo
@ -209,7 +210,7 @@ impl Store for GitStore {
Ok(target) Ok(target)
} }
fn write_symlink(&self, _path: &RepoPath, target: &str) -> Result<SymlinkId, StoreError> { fn write_symlink(&self, _path: &RepoPath, target: &str) -> Result<SymlinkId, BackendError> {
let locked_repo = self.repo.lock().unwrap(); let locked_repo = self.repo.lock().unwrap();
let oid = locked_repo.blob(target.as_bytes()).unwrap(); let oid = locked_repo.blob(target.as_bytes()).unwrap();
Ok(SymlinkId(oid.as_bytes().to_vec())) Ok(SymlinkId(oid.as_bytes().to_vec()))
@ -219,12 +220,12 @@ impl Store for GitStore {
&self.empty_tree_id &self.empty_tree_id
} }
fn read_tree(&self, _path: &RepoPath, id: &TreeId) -> StoreResult<Tree> { fn read_tree(&self, _path: &RepoPath, id: &TreeId) -> BackendResult<Tree> {
if id == &self.empty_tree_id { if id == &self.empty_tree_id {
return Ok(Tree::default()); return Ok(Tree::default());
} }
if id.0.len() != self.hash_length() { if id.0.len() != self.hash_length() {
return Err(StoreError::NotFound); return Err(BackendError::NotFound);
} }
let locked_repo = self.repo.lock().unwrap(); let locked_repo = self.repo.lock().unwrap();
@ -284,7 +285,7 @@ impl Store for GitStore {
Ok(tree) Ok(tree)
} }
fn write_tree(&self, _path: &RepoPath, contents: &Tree) -> StoreResult<TreeId> { fn write_tree(&self, _path: &RepoPath, contents: &Tree) -> BackendResult<TreeId> {
let locked_repo = self.repo.lock().unwrap(); let locked_repo = self.repo.lock().unwrap();
let mut builder = locked_repo.treebuilder(None).unwrap(); let mut builder = locked_repo.treebuilder(None).unwrap();
for entry in contents.entries() { for entry in contents.entries() {
@ -313,9 +314,9 @@ impl Store for GitStore {
Ok(TreeId(oid.as_bytes().to_vec())) Ok(TreeId(oid.as_bytes().to_vec()))
} }
fn read_commit(&self, id: &CommitId) -> StoreResult<Commit> { fn read_commit(&self, id: &CommitId) -> BackendResult<Commit> {
if id.0.len() != self.hash_length() { if id.0.len() != self.hash_length() {
return Err(StoreError::NotFound); return Err(BackendError::NotFound);
} }
let locked_repo = self.repo.lock().unwrap(); let locked_repo = self.repo.lock().unwrap();
@ -365,7 +366,7 @@ impl Store for GitStore {
Ok(commit) Ok(commit)
} }
fn write_commit(&self, contents: &Commit) -> StoreResult<CommitId> { fn write_commit(&self, contents: &Commit) -> BackendResult<CommitId> {
// TODO: We shouldn't have to create an in-memory index just to write an // TODO: We shouldn't have to create an in-memory index just to write an
// object... // object...
let locked_repo = self.repo.lock().unwrap(); let locked_repo = self.repo.lock().unwrap();
@ -405,7 +406,7 @@ impl Store for GitStore {
Ok(id) Ok(id)
} }
fn read_conflict(&self, id: &ConflictId) -> StoreResult<Conflict> { fn read_conflict(&self, id: &ConflictId) -> BackendResult<Conflict> {
let mut file = self.read_file( let mut file = self.read_file(
&RepoPath::from_internal_string("unused"), &RepoPath::from_internal_string("unused"),
&FileId(id.0.clone()), &FileId(id.0.clone()),
@ -419,7 +420,7 @@ impl Store for GitStore {
}) })
} }
fn write_conflict(&self, conflict: &Conflict) -> StoreResult<ConflictId> { fn write_conflict(&self, conflict: &Conflict) -> BackendResult<ConflictId> {
let json = serde_json::json!({ let json = serde_json::json!({
"removes": conflict_part_list_to_json(&conflict.removes), "removes": conflict_part_list_to_json(&conflict.removes),
"adds": conflict_part_list_to_json(&conflict.adds), "adds": conflict_part_list_to_json(&conflict.adds),
@ -507,7 +508,7 @@ fn bytes_vec_from_json(value: &serde_json::Value) -> Vec<u8> {
mod tests { mod tests {
use super::*; use super::*;
use crate::store::{FileId, MillisSinceEpoch}; use crate::backend::{FileId, MillisSinceEpoch};
#[test] #[test]
fn read_plain_git_commit() { fn read_plain_git_commit() {
@ -556,7 +557,7 @@ mod tests {
// Check that the git commit above got the hash we expect // Check that the git commit above got the hash we expect
assert_eq!(git_commit_id.as_bytes(), &commit_id.0); assert_eq!(git_commit_id.as_bytes(), &commit_id.0);
let store = GitStore::load(git_repo_path); let store = GitBackend::load(git_repo_path);
let commit = store.read_commit(&commit_id).unwrap(); let commit = store.read_commit(&commit_id).unwrap();
assert_eq!(&commit.change_id, &change_id); assert_eq!(&commit.change_id, &change_id);
assert_eq!(commit.parents, vec![]); assert_eq!(commit.parents, vec![]);
@ -622,7 +623,7 @@ mod tests {
let temp_dir = tempfile::tempdir().unwrap(); let temp_dir = tempfile::tempdir().unwrap();
let git_repo_path = temp_dir.path(); let git_repo_path = temp_dir.path();
let git_repo = git2::Repository::init(git_repo_path).unwrap(); let git_repo = git2::Repository::init(git_repo_path).unwrap();
let store = GitStore::load(git_repo_path); let store = GitBackend::load(git_repo_path);
let signature = Signature { let signature = Signature {
name: "Someone".to_string(), name: "Someone".to_string(),
email: "someone@example.com".to_string(), email: "someone@example.com".to_string(),
@ -656,7 +657,7 @@ mod tests {
let temp_dir = tempfile::tempdir().unwrap(); let temp_dir = tempfile::tempdir().unwrap();
let git_repo_path = temp_dir.path(); let git_repo_path = temp_dir.path();
git2::Repository::init(git_repo_path).unwrap(); git2::Repository::init(git_repo_path).unwrap();
let store = GitStore::load(git_repo_path); let store = GitBackend::load(git_repo_path);
let signature = Signature { let signature = Signature {
name: "Someone".to_string(), name: "Someone".to_string(),
email: "someone@example.com".to_string(), email: "someone@example.com".to_string(),
@ -684,7 +685,7 @@ mod tests {
Ok(_) => { Ok(_) => {
panic!("expectedly successfully wrote two commits with the same git commit object") panic!("expectedly successfully wrote two commits with the same git commit object")
} }
Err(StoreError::Other(message)) if message.contains(&expected_error_message) => {} Err(BackendError::Other(message)) if message.contains(&expected_error_message) => {}
Err(err) => panic!("unexpected error: {:?}", err), Err(err) => panic!("unexpected error: {:?}", err),
}; };
} }

View file

@ -30,9 +30,9 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use itertools::Itertools; use itertools::Itertools;
use tempfile::NamedTempFile; use tempfile::NamedTempFile;
use crate::backend::{ChangeId, CommitId};
use crate::commit::Commit; use crate::commit::Commit;
use crate::file_util::persist_content_addressed_temp_file; use crate::file_util::persist_content_addressed_temp_file;
use crate::store::{ChangeId, CommitId};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
pub struct IndexPosition(u32); pub struct IndexPosition(u32);

View file

@ -22,14 +22,14 @@ use std::sync::Arc;
use itertools::Itertools; use itertools::Itertools;
use tempfile::NamedTempFile; use tempfile::NamedTempFile;
use crate::backend::CommitId;
use crate::commit::Commit; use crate::commit::Commit;
use crate::dag_walk; use crate::dag_walk;
use crate::file_util::persist_content_addressed_temp_file; use crate::file_util::persist_content_addressed_temp_file;
use crate::index::{MutableIndex, ReadonlyIndex}; use crate::index::{MutableIndex, ReadonlyIndex};
use crate::op_store::OperationId; use crate::op_store::OperationId;
use crate::operation::Operation; use crate::operation::Operation;
use crate::store::CommitId; use crate::store::Store;
use crate::store_wrapper::StoreWrapper;
pub struct IndexStore { pub struct IndexStore {
dir: PathBuf, dir: PathBuf,
@ -50,7 +50,7 @@ impl IndexStore {
IndexStore { dir } IndexStore { dir }
} }
pub fn get_index_at_op(&self, op: &Operation, store: &StoreWrapper) -> Arc<ReadonlyIndex> { pub fn get_index_at_op(&self, op: &Operation, store: &Store) -> Arc<ReadonlyIndex> {
let op_id_hex = op.id().hex(); let op_id_hex = op.id().hex();
let op_id_file = self.dir.join("operations").join(&op_id_hex); let op_id_file = self.dir.join("operations").join(&op_id_hex);
if op_id_file.exists() { if op_id_file.exists() {
@ -89,7 +89,7 @@ impl IndexStore {
fn index_at_operation( fn index_at_operation(
&self, &self,
store: &StoreWrapper, store: &Store,
operation: &Operation, operation: &Operation,
) -> io::Result<Arc<ReadonlyIndex>> { ) -> io::Result<Arc<ReadonlyIndex>> {
let view = operation.view(); let view = operation.view();
@ -163,7 +163,7 @@ impl IndexStore {
// Returns the ancestors of heads with parents and predecessors come before the // Returns the ancestors of heads with parents and predecessors come before the
// commit itself // commit itself
fn topo_order_earlier_first( fn topo_order_earlier_first(
store: &StoreWrapper, store: &Store,
heads: Vec<CommitId>, heads: Vec<CommitId>,
parent_file: Option<Arc<ReadonlyIndex>>, parent_file: Option<Arc<ReadonlyIndex>>,
) -> Vec<Commit> { ) -> Vec<Commit> {

View file

@ -24,6 +24,7 @@ extern crate pest_derive;
#[macro_use] #[macro_use]
extern crate maplit; extern crate maplit;
pub mod backend;
pub mod commit; pub mod commit;
pub mod commit_builder; pub mod commit_builder;
pub mod conflicts; pub mod conflicts;
@ -33,11 +34,11 @@ pub mod evolution;
pub mod file_util; pub mod file_util;
pub mod files; pub mod files;
pub mod git; pub mod git;
pub mod git_store; pub mod git_backend;
pub mod gitignore; pub mod gitignore;
pub mod index; pub mod index;
pub mod index_store; pub mod index_store;
pub mod local_store; pub mod local_backend;
pub mod lock; pub mod lock;
pub mod matchers; pub mod matchers;
pub mod op_heads_store; pub mod op_heads_store;
@ -53,7 +54,6 @@ pub mod rewrite;
pub mod settings; pub mod settings;
pub mod simple_op_store; pub mod simple_op_store;
pub mod store; pub mod store;
pub mod store_wrapper;
pub mod testutils; pub mod testutils;
pub mod transaction; pub mod transaction;
pub mod tree; pub mod tree;

View file

@ -22,55 +22,56 @@ use blake2::{Blake2b, Digest};
use protobuf::{Message, ProtobufError}; use protobuf::{Message, ProtobufError};
use tempfile::{NamedTempFile, PersistError}; use tempfile::{NamedTempFile, PersistError};
use crate::backend::{
Backend, BackendError, BackendResult, ChangeId, Commit, CommitId, Conflict, ConflictId,
ConflictPart, FileId, MillisSinceEpoch, Signature, SymlinkId, Timestamp, Tree, TreeId,
TreeValue,
};
use crate::file_util::persist_content_addressed_temp_file; use crate::file_util::persist_content_addressed_temp_file;
use crate::repo_path::{RepoPath, RepoPathComponent}; use crate::repo_path::{RepoPath, RepoPathComponent};
use crate::store::{
ChangeId, Commit, CommitId, Conflict, ConflictId, ConflictPart, FileId, MillisSinceEpoch,
Signature, Store, StoreError, StoreResult, SymlinkId, Timestamp, Tree, TreeId, TreeValue,
};
impl From<std::io::Error> for StoreError { impl From<std::io::Error> for BackendError {
fn from(err: std::io::Error) -> Self { fn from(err: std::io::Error) -> Self {
StoreError::Other(err.to_string()) BackendError::Other(err.to_string())
} }
} }
impl From<PersistError> for StoreError { impl From<PersistError> for BackendError {
fn from(err: PersistError) -> Self { fn from(err: PersistError) -> Self {
StoreError::Other(err.to_string()) BackendError::Other(err.to_string())
} }
} }
impl From<ProtobufError> for StoreError { impl From<ProtobufError> for BackendError {
fn from(err: ProtobufError) -> Self { fn from(err: ProtobufError) -> Self {
StoreError::Other(err.to_string()) BackendError::Other(err.to_string())
} }
} }
#[derive(Debug)] #[derive(Debug)]
pub struct LocalStore { pub struct LocalBackend {
path: PathBuf, path: PathBuf,
empty_tree_id: TreeId, empty_tree_id: TreeId,
} }
impl LocalStore { impl LocalBackend {
pub fn init(store_path: PathBuf) -> Self { pub fn init(store_path: PathBuf) -> Self {
fs::create_dir(store_path.join("commits")).unwrap(); fs::create_dir(store_path.join("commits")).unwrap();
fs::create_dir(store_path.join("trees")).unwrap(); fs::create_dir(store_path.join("trees")).unwrap();
fs::create_dir(store_path.join("files")).unwrap(); fs::create_dir(store_path.join("files")).unwrap();
fs::create_dir(store_path.join("symlinks")).unwrap(); fs::create_dir(store_path.join("symlinks")).unwrap();
fs::create_dir(store_path.join("conflicts")).unwrap(); fs::create_dir(store_path.join("conflicts")).unwrap();
let store = Self::load(store_path); let backend = Self::load(store_path);
let empty_tree_id = store let empty_tree_id = backend
.write_tree(&RepoPath::root(), &Tree::default()) .write_tree(&RepoPath::root(), &Tree::default())
.unwrap(); .unwrap();
assert_eq!(empty_tree_id, store.empty_tree_id); assert_eq!(empty_tree_id, backend.empty_tree_id);
store backend
} }
pub fn load(store_path: PathBuf) -> Self { pub fn load(store_path: PathBuf) -> Self {
let empty_tree_id = TreeId(hex::decode("786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce").unwrap()); let empty_tree_id = TreeId(hex::decode("786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce").unwrap());
LocalStore { LocalBackend {
path: store_path, path: store_path,
empty_tree_id, empty_tree_id,
} }
@ -97,15 +98,15 @@ impl LocalStore {
} }
} }
fn not_found_to_store_error(err: std::io::Error) -> StoreError { fn not_found_to_backend_error(err: std::io::Error) -> BackendError {
if err.kind() == ErrorKind::NotFound { if err.kind() == ErrorKind::NotFound {
StoreError::NotFound BackendError::NotFound
} else { } else {
StoreError::from(err) BackendError::from(err)
} }
} }
impl Store for LocalStore { impl Backend for LocalBackend {
fn hash_length(&self) -> usize { fn hash_length(&self) -> usize {
64 64
} }
@ -114,13 +115,13 @@ impl Store for LocalStore {
None None
} }
fn read_file(&self, _path: &RepoPath, id: &FileId) -> StoreResult<Box<dyn Read>> { fn read_file(&self, _path: &RepoPath, id: &FileId) -> BackendResult<Box<dyn Read>> {
let path = self.file_path(id); let path = self.file_path(id);
let file = File::open(path).map_err(not_found_to_store_error)?; let file = File::open(path).map_err(not_found_to_backend_error)?;
Ok(Box::new(zstd::Decoder::new(file)?)) Ok(Box::new(zstd::Decoder::new(file)?))
} }
fn write_file(&self, _path: &RepoPath, contents: &mut dyn Read) -> StoreResult<FileId> { fn write_file(&self, _path: &RepoPath, contents: &mut dyn Read) -> BackendResult<FileId> {
let temp_file = NamedTempFile::new_in(&self.path)?; let temp_file = NamedTempFile::new_in(&self.path)?;
let mut encoder = zstd::Encoder::new(temp_file.as_file(), 0)?; let mut encoder = zstd::Encoder::new(temp_file.as_file(), 0)?;
let mut hasher = Blake2b::new(); let mut hasher = Blake2b::new();
@ -145,15 +146,15 @@ impl Store for LocalStore {
Ok(id) Ok(id)
} }
fn read_symlink(&self, _path: &RepoPath, id: &SymlinkId) -> Result<String, StoreError> { fn read_symlink(&self, _path: &RepoPath, id: &SymlinkId) -> Result<String, BackendError> {
let path = self.symlink_path(id); let path = self.symlink_path(id);
let mut file = File::open(path).map_err(not_found_to_store_error)?; let mut file = File::open(path).map_err(not_found_to_backend_error)?;
let mut target = String::new(); let mut target = String::new();
file.read_to_string(&mut target).unwrap(); file.read_to_string(&mut target).unwrap();
Ok(target) Ok(target)
} }
fn write_symlink(&self, _path: &RepoPath, target: &str) -> Result<SymlinkId, StoreError> { fn write_symlink(&self, _path: &RepoPath, target: &str) -> Result<SymlinkId, BackendError> {
let mut temp_file = NamedTempFile::new_in(&self.path)?; let mut temp_file = NamedTempFile::new_in(&self.path)?;
temp_file.write_all(target.as_bytes())?; temp_file.write_all(target.as_bytes())?;
let mut hasher = Blake2b::new(); let mut hasher = Blake2b::new();
@ -168,15 +169,15 @@ impl Store for LocalStore {
&self.empty_tree_id &self.empty_tree_id
} }
fn read_tree(&self, _path: &RepoPath, id: &TreeId) -> StoreResult<Tree> { fn read_tree(&self, _path: &RepoPath, id: &TreeId) -> BackendResult<Tree> {
let path = self.tree_path(id); let path = self.tree_path(id);
let mut file = File::open(path).map_err(not_found_to_store_error)?; let mut file = File::open(path).map_err(not_found_to_backend_error)?;
let proto: crate::protos::store::Tree = Message::parse_from_reader(&mut file)?; let proto: crate::protos::store::Tree = Message::parse_from_reader(&mut file)?;
Ok(tree_from_proto(&proto)) Ok(tree_from_proto(&proto))
} }
fn write_tree(&self, _path: &RepoPath, tree: &Tree) -> StoreResult<TreeId> { fn write_tree(&self, _path: &RepoPath, tree: &Tree) -> BackendResult<TreeId> {
let temp_file = NamedTempFile::new_in(&self.path)?; let temp_file = NamedTempFile::new_in(&self.path)?;
let proto = tree_to_proto(tree); let proto = tree_to_proto(tree);
@ -191,15 +192,15 @@ impl Store for LocalStore {
Ok(id) Ok(id)
} }
fn read_commit(&self, id: &CommitId) -> StoreResult<Commit> { fn read_commit(&self, id: &CommitId) -> BackendResult<Commit> {
let path = self.commit_path(id); let path = self.commit_path(id);
let mut file = File::open(path).map_err(not_found_to_store_error)?; let mut file = File::open(path).map_err(not_found_to_backend_error)?;
let proto: crate::protos::store::Commit = Message::parse_from_reader(&mut file)?; let proto: crate::protos::store::Commit = Message::parse_from_reader(&mut file)?;
Ok(commit_from_proto(&proto)) Ok(commit_from_proto(&proto))
} }
fn write_commit(&self, commit: &Commit) -> StoreResult<CommitId> { fn write_commit(&self, commit: &Commit) -> BackendResult<CommitId> {
let temp_file = NamedTempFile::new_in(&self.path)?; let temp_file = NamedTempFile::new_in(&self.path)?;
let proto = commit_to_proto(commit); let proto = commit_to_proto(commit);
@ -214,15 +215,15 @@ impl Store for LocalStore {
Ok(id) Ok(id)
} }
fn read_conflict(&self, id: &ConflictId) -> StoreResult<Conflict> { fn read_conflict(&self, id: &ConflictId) -> BackendResult<Conflict> {
let path = self.conflict_path(id); let path = self.conflict_path(id);
let mut file = File::open(path).map_err(not_found_to_store_error)?; let mut file = File::open(path).map_err(not_found_to_backend_error)?;
let proto: crate::protos::store::Conflict = Message::parse_from_reader(&mut file)?; let proto: crate::protos::store::Conflict = Message::parse_from_reader(&mut file)?;
Ok(conflict_from_proto(&proto)) Ok(conflict_from_proto(&proto))
} }
fn write_conflict(&self, conflict: &Conflict) -> StoreResult<ConflictId> { fn write_conflict(&self, conflict: &Conflict) -> BackendResult<ConflictId> {
let temp_file = NamedTempFile::new_in(&self.path)?; let temp_file = NamedTempFile::new_in(&self.path)?;
let proto = conflict_to_proto(conflict); let proto = conflict_to_proto(conflict);

View file

@ -19,11 +19,11 @@ use std::sync::Arc;
use itertools::Itertools; use itertools::Itertools;
use thiserror::Error; use thiserror::Error;
use crate::backend::Timestamp;
use crate::lock::FileLock; use crate::lock::FileLock;
use crate::op_store::{OpStore, OperationId, OperationMetadata}; use crate::op_store::{OpStore, OperationId, OperationMetadata};
use crate::operation::Operation; use crate::operation::Operation;
use crate::repo::RepoLoader; use crate::repo::RepoLoader;
use crate::store::Timestamp;
use crate::transaction::UnpublishedOperation; use crate::transaction::UnpublishedOperation;
use crate::{dag_walk, op_store}; use crate::{dag_walk, op_store};

View file

@ -15,7 +15,7 @@
use std::collections::{BTreeMap, HashMap, HashSet}; use std::collections::{BTreeMap, HashMap, HashSet};
use std::fmt::{Debug, Error, Formatter}; use std::fmt::{Debug, Error, Formatter};
use crate::store::{CommitId, Timestamp}; use crate::backend::{CommitId, Timestamp};
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct ViewId(pub Vec<u8>); pub struct ViewId(pub Vec<u8>);

View file

@ -18,9 +18,9 @@ use std::fmt::{Debug, Error, Formatter};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::sync::Arc; use std::sync::Arc;
use crate::backend::CommitId;
use crate::op_store; use crate::op_store;
use crate::op_store::{OpStore, OperationId, ViewId}; use crate::op_store::{OpStore, OperationId, ViewId};
use crate::store::CommitId;
#[derive(Clone)] #[derive(Clone)]
pub struct Operation { pub struct Operation {

View file

@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use crate::backend::CommitId;
use crate::index::IndexRef; use crate::index::IndexRef;
use crate::op_store::{BranchTarget, RefTarget}; use crate::op_store::{BranchTarget, RefTarget};
use crate::store::CommitId;
pub fn merge_ref_targets( pub fn merge_ref_targets(
index: IndexRef, index: IndexRef,

View file

@ -21,25 +21,25 @@ use std::sync::{Arc, Mutex, MutexGuard};
use thiserror::Error; use thiserror::Error;
use crate::backend::{Backend, BackendError, CommitId};
use crate::commit::Commit; use crate::commit::Commit;
use crate::commit_builder::{new_change_id, signature, CommitBuilder}; use crate::commit_builder::{new_change_id, signature, CommitBuilder};
use crate::dag_walk::topo_order_reverse; use crate::dag_walk::topo_order_reverse;
use crate::evolution::{EvolutionRef, MutableEvolution, ReadonlyEvolution}; use crate::evolution::{EvolutionRef, MutableEvolution, ReadonlyEvolution};
use crate::git_store::GitStore; use crate::git_backend::GitBackend;
use crate::index::{IndexRef, MutableIndex, ReadonlyIndex}; use crate::index::{IndexRef, MutableIndex, ReadonlyIndex};
use crate::index_store::IndexStore; use crate::index_store::IndexStore;
use crate::local_store::LocalStore; use crate::local_backend::LocalBackend;
use crate::op_heads_store::OpHeadsStore; use crate::op_heads_store::OpHeadsStore;
use crate::op_store::{BranchTarget, OpStore, OperationId, RefTarget}; use crate::op_store::{BranchTarget, OpStore, OperationId, RefTarget};
use crate::operation::Operation; use crate::operation::Operation;
use crate::settings::{RepoSettings, UserSettings}; use crate::settings::{RepoSettings, UserSettings};
use crate::simple_op_store::SimpleOpStore; use crate::simple_op_store::SimpleOpStore;
use crate::store::{CommitId, Store, StoreError}; use crate::store::Store;
use crate::store_wrapper::StoreWrapper;
use crate::transaction::Transaction; use crate::transaction::Transaction;
use crate::view::{RefName, View}; use crate::view::{RefName, View};
use crate::working_copy::WorkingCopy; use crate::working_copy::WorkingCopy;
use crate::{conflicts, op_store, store}; use crate::{backend, conflicts, op_store};
#[derive(Debug, Error, PartialEq, Eq)] #[derive(Debug, Error, PartialEq, Eq)]
pub enum RepoError { pub enum RepoError {
@ -49,11 +49,11 @@ pub enum RepoError {
Other(String), Other(String),
} }
impl From<StoreError> for RepoError { impl From<BackendError> for RepoError {
fn from(err: StoreError) -> Self { fn from(err: BackendError) -> Self {
match err { match err {
StoreError::NotFound => RepoError::NotFound, BackendError::NotFound => RepoError::NotFound,
StoreError::Other(description) => RepoError::Other(description), BackendError::Other(description) => RepoError::Other(description),
} }
} }
} }
@ -69,7 +69,7 @@ pub enum RepoRef<'a> {
} }
impl<'a> RepoRef<'a> { impl<'a> RepoRef<'a> {
pub fn store(&self) -> &Arc<StoreWrapper> { pub fn store(&self) -> &Arc<Store> {
match self { match self {
RepoRef::Readonly(repo) => repo.store(), RepoRef::Readonly(repo) => repo.store(),
RepoRef::Mutable(repo) => repo.store(), RepoRef::Mutable(repo) => repo.store(),
@ -108,7 +108,7 @@ impl<'a> RepoRef<'a> {
pub struct ReadonlyRepo { pub struct ReadonlyRepo {
repo_path: PathBuf, repo_path: PathBuf,
wc_path: PathBuf, wc_path: PathBuf,
store: Arc<StoreWrapper>, store: Arc<Store>,
op_store: Arc<dyn OpStore>, op_store: Arc<dyn OpStore>,
op_heads_store: Arc<OpHeadsStore>, op_heads_store: Arc<OpHeadsStore>,
operation: Operation, operation: Operation,
@ -150,11 +150,11 @@ impl ReadonlyRepo {
let repo_path = ReadonlyRepo::init_repo_dir(&wc_path)?; let repo_path = ReadonlyRepo::init_repo_dir(&wc_path)?;
let store_path = repo_path.join("store"); let store_path = repo_path.join("store");
fs::create_dir(&store_path).unwrap(); fs::create_dir(&store_path).unwrap();
let store = Box::new(LocalStore::init(store_path)); let backend = Box::new(LocalBackend::init(store_path));
Ok(ReadonlyRepo::init(settings, repo_path, wc_path, store)) Ok(ReadonlyRepo::init(settings, repo_path, wc_path, backend))
} }
/// Initializes a repo with a new Git store in .jj/git/ (bare Git repo) /// Initializes a repo with a new Git backend in .jj/git/ (bare Git repo)
pub fn init_internal_git( pub fn init_internal_git(
settings: &UserSettings, settings: &UserSettings,
wc_path: PathBuf, wc_path: PathBuf,
@ -166,11 +166,11 @@ impl ReadonlyRepo {
let git_store_path = fs::canonicalize(git_store_path).unwrap(); let git_store_path = fs::canonicalize(git_store_path).unwrap();
let mut store_file = File::create(store_path).unwrap(); let mut store_file = File::create(store_path).unwrap();
store_file.write_all(b"git: git").unwrap(); store_file.write_all(b"git: git").unwrap();
let store = Box::new(GitStore::load(&git_store_path)); let backend = Box::new(GitBackend::load(&git_store_path));
Ok(ReadonlyRepo::init(settings, repo_path, wc_path, store)) Ok(ReadonlyRepo::init(settings, repo_path, wc_path, backend))
} }
/// Initializes a repo with an existing Git store at the specified path /// Initializes a repo with an existing Git backend at the specified path
pub fn init_external_git( pub fn init_external_git(
settings: &UserSettings, settings: &UserSettings,
wc_path: PathBuf, wc_path: PathBuf,
@ -183,8 +183,8 @@ impl ReadonlyRepo {
store_file store_file
.write_all(format!("git: {}", git_store_path.to_str().unwrap()).as_bytes()) .write_all(format!("git: {}", git_store_path.to_str().unwrap()).as_bytes())
.unwrap(); .unwrap();
let store = Box::new(GitStore::load(&git_store_path)); let backend = Box::new(GitBackend::load(&git_store_path));
Ok(ReadonlyRepo::init(settings, repo_path, wc_path, store)) Ok(ReadonlyRepo::init(settings, repo_path, wc_path, backend))
} }
fn init_repo_dir(wc_path: &Path) -> Result<PathBuf, RepoInitError> { fn init_repo_dir(wc_path: &Path) -> Result<PathBuf, RepoInitError> {
@ -201,10 +201,10 @@ impl ReadonlyRepo {
user_settings: &UserSettings, user_settings: &UserSettings,
repo_path: PathBuf, repo_path: PathBuf,
wc_path: PathBuf, wc_path: PathBuf,
store: Box<dyn Store>, backend: Box<dyn Backend>,
) -> Arc<ReadonlyRepo> { ) -> Arc<ReadonlyRepo> {
let repo_settings = user_settings.with_repo(&repo_path).unwrap(); let repo_settings = user_settings.with_repo(&repo_path).unwrap();
let store = StoreWrapper::new(store); let store = Store::new(backend);
fs::create_dir(repo_path.join("working_copy")).unwrap(); fs::create_dir(repo_path.join("working_copy")).unwrap();
let working_copy = WorkingCopy::init( let working_copy = WorkingCopy::init(
@ -215,7 +215,7 @@ impl ReadonlyRepo {
fs::create_dir(repo_path.join("view")).unwrap(); fs::create_dir(repo_path.join("view")).unwrap();
let signature = signature(user_settings); let signature = signature(user_settings);
let checkout_commit = store::Commit { let checkout_commit = backend::Commit {
parents: vec![], parents: vec![],
predecessors: vec![], predecessors: vec![],
root_tree: store.empty_tree_id().clone(), root_tree: store.empty_tree_id().clone(),
@ -352,7 +352,7 @@ impl ReadonlyRepo {
self.working_copy.as_ref().lock().unwrap() self.working_copy.as_ref().lock().unwrap()
} }
pub fn store(&self) -> &Arc<StoreWrapper> { pub fn store(&self) -> &Arc<Store> {
&self.store &self.store
} }
@ -396,7 +396,7 @@ pub struct RepoLoader {
wc_path: PathBuf, wc_path: PathBuf,
repo_path: PathBuf, repo_path: PathBuf,
repo_settings: RepoSettings, repo_settings: RepoSettings,
store: Arc<StoreWrapper>, store: Arc<Store>,
op_store: Arc<dyn OpStore>, op_store: Arc<dyn OpStore>,
op_heads_store: Arc<OpHeadsStore>, op_heads_store: Arc<OpHeadsStore>,
index_store: Arc<IndexStore>, index_store: Arc<IndexStore>,
@ -423,7 +423,7 @@ impl RepoLoader {
) -> Result<RepoLoader, RepoLoadError> { ) -> Result<RepoLoader, RepoLoadError> {
let repo_path = find_repo_dir(&wc_path).ok_or(RepoLoadError::NoRepoHere(wc_path))?; let repo_path = find_repo_dir(&wc_path).ok_or(RepoLoadError::NoRepoHere(wc_path))?;
let wc_path = repo_path.parent().unwrap().to_owned(); let wc_path = repo_path.parent().unwrap().to_owned();
let store = StoreWrapper::load_store(&repo_path); let store = Store::load_store(&repo_path);
let repo_settings = user_settings.with_repo(&repo_path).unwrap(); let repo_settings = user_settings.with_repo(&repo_path).unwrap();
let op_store: Arc<dyn OpStore> = Arc::new(SimpleOpStore::load(repo_path.join("op_store"))); let op_store: Arc<dyn OpStore> = Arc::new(SimpleOpStore::load(repo_path.join("op_store")));
let op_heads_store = Arc::new(OpHeadsStore::load(repo_path.join("op_heads"))); let op_heads_store = Arc::new(OpHeadsStore::load(repo_path.join("op_heads")));
@ -439,7 +439,7 @@ impl RepoLoader {
}) })
} }
pub fn store(&self) -> &Arc<StoreWrapper> { pub fn store(&self) -> &Arc<Store> {
&self.store &self.store
} }
@ -548,7 +548,7 @@ impl MutableRepo {
&self.base_repo &self.base_repo
} }
pub fn store(&self) -> &Arc<StoreWrapper> { pub fn store(&self) -> &Arc<Store> {
self.base_repo.store() self.base_repo.store()
} }
@ -593,7 +593,7 @@ impl MutableRepo {
self.evolution.lock().unwrap().take(); self.evolution.lock().unwrap().take();
} }
pub fn write_commit(&mut self, commit: store::Commit) -> Commit { pub fn write_commit(&mut self, commit: backend::Commit) -> Commit {
let commit = self.store().write_commit(commit); let commit = self.store().write_commit(commit);
self.add_head(&commit); self.add_head(&commit);
commit commit

View file

@ -23,11 +23,11 @@ use pest::iterators::Pairs;
use pest::Parser; use pest::Parser;
use thiserror::Error; use thiserror::Error;
use crate::backend::{BackendError, CommitId};
use crate::commit::Commit; use crate::commit::Commit;
use crate::index::{HexPrefix, IndexEntry, IndexPosition, PrefixResolution, RevWalk}; use crate::index::{HexPrefix, IndexEntry, IndexPosition, PrefixResolution, RevWalk};
use crate::repo::RepoRef; use crate::repo::RepoRef;
use crate::revset_graph_iterator::RevsetGraphIterator; use crate::revset_graph_iterator::RevsetGraphIterator;
use crate::store::{CommitId, StoreError};
#[derive(Debug, Error, PartialEq, Eq)] #[derive(Debug, Error, PartialEq, Eq)]
pub enum RevsetError { pub enum RevsetError {
@ -38,7 +38,7 @@ pub enum RevsetError {
#[error("Change id prefix \"{0}\" is ambiguous")] #[error("Change id prefix \"{0}\" is ambiguous")]
AmbiguousChangeIdPrefix(String), AmbiguousChangeIdPrefix(String),
#[error("Unexpected error from store: {0}")] #[error("Unexpected error from store: {0}")]
StoreError(#[from] StoreError), StoreError(#[from] BackendError),
} }
fn resolve_git_ref(repo: RepoRef, symbol: &str) -> Result<Vec<CommitId>, RevsetError> { fn resolve_git_ref(repo: RepoRef, symbol: &str) -> Result<Vec<CommitId>, RevsetError> {
@ -75,7 +75,7 @@ fn resolve_commit_id(repo: RepoRef, symbol: &str) -> Result<Vec<CommitId>, Revse
let commit_id = CommitId(binary_commit_id); let commit_id = CommitId(binary_commit_id);
match repo.store().get_commit(&commit_id) { match repo.store().get_commit(&commit_id) {
Ok(_) => return Ok(vec![commit_id]), Ok(_) => return Ok(vec![commit_id]),
Err(StoreError::NotFound) => {} // fall through Err(BackendError::NotFound) => {} // fall through
Err(err) => return Err(RevsetError::StoreError(err)), Err(err) => return Err(RevsetError::StoreError(err)),
} }
} }

View file

@ -16,13 +16,13 @@ use std::collections::{HashMap, HashSet};
use itertools::Itertools; use itertools::Itertools;
use crate::backend::CommitId;
use crate::commit::Commit; use crate::commit::Commit;
use crate::commit_builder::CommitBuilder; use crate::commit_builder::CommitBuilder;
use crate::repo::{MutableRepo, RepoRef}; use crate::repo::{MutableRepo, RepoRef};
use crate::repo_path::RepoPath; use crate::repo_path::RepoPath;
use crate::revset::RevsetExpression; use crate::revset::RevsetExpression;
use crate::settings::UserSettings; use crate::settings::UserSettings;
use crate::store::CommitId;
use crate::tree::{merge_trees, Tree}; use crate::tree::{merge_trees, Tree};
pub fn merge_commit_trees(repo: RepoRef, commits: &[Commit]) -> Tree { pub fn merge_commit_trees(repo: RepoRef, commits: &[Commit]) -> Tree {

View file

@ -24,12 +24,12 @@ use itertools::Itertools;
use protobuf::{Message, ProtobufError}; use protobuf::{Message, ProtobufError};
use tempfile::{NamedTempFile, PersistError}; use tempfile::{NamedTempFile, PersistError};
use crate::backend::{CommitId, MillisSinceEpoch, Timestamp};
use crate::file_util::persist_content_addressed_temp_file; use crate::file_util::persist_content_addressed_temp_file;
use crate::op_store::{ use crate::op_store::{
BranchTarget, OpStore, OpStoreError, OpStoreResult, Operation, OperationId, OperationMetadata, BranchTarget, OpStore, OpStoreError, OpStoreResult, Operation, OperationId, OperationMetadata,
RefTarget, View, ViewId, RefTarget, View, ViewId,
}; };
use crate::store::{CommitId, MillisSinceEpoch, Timestamp};
impl From<std::io::Error> for OpStoreError { impl From<std::io::Error> for OpStoreError {
fn from(err: std::io::Error) -> Self { fn from(err: std::io::Error) -> Self {

View file

@ -12,307 +12,217 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::collections::BTreeMap; use std::collections::HashMap;
use std::fmt::{Debug, Error, Formatter}; use std::fs::File;
use std::io::Read; use std::io::Read;
use std::result::Result; use std::path::{Path, PathBuf};
use std::vec::Vec; use std::sync::{Arc, RwLock, Weak};
use thiserror::Error; use crate::backend;
use crate::backend::{
Backend, BackendResult, ChangeId, CommitId, Conflict, ConflictId, FileId, MillisSinceEpoch,
Signature, SymlinkId, Timestamp, TreeId,
};
use crate::commit::Commit;
use crate::git_backend::GitBackend;
use crate::local_backend::LocalBackend;
use crate::repo_path::RepoPath;
use crate::tree::Tree;
use crate::tree_builder::TreeBuilder;
use crate::repo_path::{RepoPath, RepoPathComponent}; /// Wraps the low-level backend and makes it return more convenient types. Also
/// adds the root commit and adds caching.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)] #[derive(Debug)]
pub struct CommitId(pub Vec<u8>); pub struct Store {
weak_self: Option<Weak<Store>>,
impl Debug for CommitId { backend: Box<dyn Backend>,
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { root_commit_id: CommitId,
f.debug_tuple("CommitId").field(&self.hex()).finish() commit_cache: RwLock<HashMap<CommitId, Arc<backend::Commit>>>,
} tree_cache: RwLock<HashMap<(RepoPath, TreeId), Arc<backend::Tree>>>,
} }
impl CommitId { impl Store {
pub fn from_hex(hex: &str) -> Self { pub fn new(backend: Box<dyn Backend>) -> Arc<Self> {
CommitId(hex::decode(hex).unwrap()) let root_commit_id = CommitId(vec![0; backend.hash_length()]);
let mut wrapper = Arc::new(Store {
weak_self: None,
backend,
root_commit_id,
commit_cache: Default::default(),
tree_cache: Default::default(),
});
let weak_self = Arc::downgrade(&wrapper);
let mut ref_mut = unsafe { Arc::get_mut_unchecked(&mut wrapper) };
ref_mut.weak_self = Some(weak_self);
wrapper
} }
pub fn hex(&self) -> String { pub fn load_store(repo_path: &Path) -> Arc<Store> {
hex::encode(&self.0) let store_path = repo_path.join("store");
let backend: Box<dyn Backend>;
// TODO: Perhaps .jj/store should always be a directory. Then .jj/git would live
// inside that directory and this function would not need to know the repo path
// (only the store path). Maybe there would be a .jj/store/format file
// indicating which kind of store it is?
if store_path.is_dir() {
backend = Box::new(LocalBackend::load(store_path));
} else {
let mut store_file = File::open(store_path).unwrap();
let mut buf = Vec::new();
store_file.read_to_end(&mut buf).unwrap();
let contents = String::from_utf8(buf).unwrap();
assert!(contents.starts_with("git: "));
let git_backend_path_str = contents[5..].to_string();
let git_backend_path =
std::fs::canonicalize(repo_path.join(PathBuf::from(git_backend_path_str))).unwrap();
backend = Box::new(GitBackend::load(&git_backend_path));
}
Store::new(backend)
}
pub fn hash_length(&self) -> usize {
self.backend.hash_length()
}
pub fn git_repo(&self) -> Option<git2::Repository> {
self.backend.git_repo()
}
pub fn empty_tree_id(&self) -> &TreeId {
self.backend.empty_tree_id()
}
pub fn root_commit_id(&self) -> &CommitId {
&self.root_commit_id
}
pub fn root_commit(&self) -> Commit {
self.get_commit(&self.root_commit_id).unwrap()
}
pub fn get_commit(&self, id: &CommitId) -> BackendResult<Commit> {
let data = self.get_backend_commit(id)?;
Ok(Commit::new(
self.weak_self.as_ref().unwrap().upgrade().unwrap(),
id.clone(),
data,
))
}
fn make_root_commit(&self) -> backend::Commit {
let timestamp = Timestamp {
timestamp: MillisSinceEpoch(0),
tz_offset: 0,
};
let signature = Signature {
name: String::new(),
email: String::new(),
timestamp,
};
let change_id = ChangeId(vec![0; 16]);
backend::Commit {
parents: vec![],
predecessors: vec![],
root_tree: self.backend.empty_tree_id().clone(),
change_id,
description: String::new(),
author: signature.clone(),
committer: signature,
is_open: false,
is_pruned: false,
}
}
fn get_backend_commit(&self, id: &CommitId) -> BackendResult<Arc<backend::Commit>> {
{
let read_locked_cached = self.commit_cache.read().unwrap();
if let Some(data) = read_locked_cached.get(id).cloned() {
return Ok(data);
}
}
let commit = if id == self.root_commit_id() {
self.make_root_commit()
} else {
self.backend.read_commit(id)?
};
let data = Arc::new(commit);
let mut write_locked_cache = self.commit_cache.write().unwrap();
write_locked_cache.insert(id.clone(), data.clone());
Ok(data)
}
pub fn write_commit(&self, commit: backend::Commit) -> Commit {
let commit_id = self.backend.write_commit(&commit).unwrap();
let data = Arc::new(commit);
{
let mut write_locked_cache = self.commit_cache.write().unwrap();
write_locked_cache.insert(commit_id.clone(), data.clone());
}
let commit = Commit::new(
self.weak_self.as_ref().unwrap().upgrade().unwrap(),
commit_id,
data,
);
commit
}
pub fn get_tree(&self, dir: &RepoPath, id: &TreeId) -> BackendResult<Tree> {
let data = self.get_backend_tree(dir, id)?;
Ok(Tree::new(
self.weak_self.as_ref().unwrap().upgrade().unwrap(),
dir.clone(),
id.clone(),
data,
))
}
fn get_backend_tree(&self, dir: &RepoPath, id: &TreeId) -> BackendResult<Arc<backend::Tree>> {
let key = (dir.clone(), id.clone());
{
let read_locked_cache = self.tree_cache.read().unwrap();
if let Some(data) = read_locked_cache.get(&key).cloned() {
return Ok(data);
}
}
let data = Arc::new(self.backend.read_tree(dir, id)?);
let mut write_locked_cache = self.tree_cache.write().unwrap();
write_locked_cache.insert(key, data.clone());
Ok(data)
}
pub fn write_tree(&self, path: &RepoPath, contents: &backend::Tree) -> BackendResult<TreeId> {
// TODO: This should also do caching like write_commit does.
self.backend.write_tree(path, contents)
}
pub fn read_file(&self, path: &RepoPath, id: &FileId) -> BackendResult<Box<dyn Read>> {
self.backend.read_file(path, id)
}
pub fn write_file(&self, path: &RepoPath, contents: &mut dyn Read) -> BackendResult<FileId> {
self.backend.write_file(path, contents)
}
pub fn read_symlink(&self, path: &RepoPath, id: &SymlinkId) -> BackendResult<String> {
self.backend.read_symlink(path, id)
}
pub fn write_symlink(&self, path: &RepoPath, contents: &str) -> BackendResult<SymlinkId> {
self.backend.write_symlink(path, contents)
}
pub fn read_conflict(&self, id: &ConflictId) -> BackendResult<Conflict> {
self.backend.read_conflict(id)
}
pub fn write_conflict(&self, contents: &Conflict) -> BackendResult<ConflictId> {
self.backend.write_conflict(contents)
}
pub fn tree_builder(&self, base_tree_id: TreeId) -> TreeBuilder {
TreeBuilder::new(
self.weak_self.as_ref().unwrap().upgrade().unwrap(),
base_tree_id,
)
} }
} }
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct ChangeId(pub Vec<u8>);
impl Debug for ChangeId {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_tuple("ChangeId").field(&self.hex()).finish()
}
}
impl ChangeId {
pub fn from_hex(hex: &str) -> Self {
ChangeId(hex::decode(hex).unwrap())
}
pub fn hex(&self) -> String {
hex::encode(&self.0)
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct TreeId(pub Vec<u8>);
impl Debug for TreeId {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_tuple("TreeId").field(&self.hex()).finish()
}
}
impl TreeId {
pub fn hex(&self) -> String {
hex::encode(&self.0)
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct FileId(pub Vec<u8>);
impl Debug for FileId {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_tuple("FileId").field(&self.hex()).finish()
}
}
impl FileId {
pub fn hex(&self) -> String {
hex::encode(&self.0)
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct SymlinkId(pub Vec<u8>);
impl Debug for SymlinkId {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_tuple("SymlinkId").field(&self.hex()).finish()
}
}
impl SymlinkId {
pub fn hex(&self) -> String {
hex::encode(&self.0)
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct ConflictId(pub Vec<u8>);
impl Debug for ConflictId {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_tuple("ConflictId").field(&self.hex()).finish()
}
}
impl ConflictId {
pub fn hex(&self) -> String {
hex::encode(&self.0)
}
}
pub enum Phase {
Public,
Draft,
}
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord)]
pub struct MillisSinceEpoch(pub u64);
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord)]
pub struct Timestamp {
pub timestamp: MillisSinceEpoch,
// time zone offset in minutes
pub tz_offset: i32,
}
impl Timestamp {
pub fn now() -> Self {
let now = chrono::offset::Local::now();
Self {
timestamp: MillisSinceEpoch(now.timestamp_millis() as u64),
tz_offset: now.offset().local_minus_utc() / 60,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Signature {
pub name: String,
pub email: String,
pub timestamp: Timestamp,
}
#[derive(Debug, Clone)]
pub struct Commit {
pub parents: Vec<CommitId>,
pub predecessors: Vec<CommitId>,
pub root_tree: TreeId,
pub change_id: ChangeId,
pub description: String,
pub author: Signature,
pub committer: Signature,
pub is_open: bool,
pub is_pruned: bool,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ConflictPart {
// TODO: Store e.g. CommitId here too? Labels (theirs/ours/base)? Would those still be
// useful e.g. after rebasing this conflict?
pub value: TreeValue,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Conflict {
// A conflict is represented by a list of positive and negative states that need to be applied.
// In a simple 3-way merge of B and C with merge base A, the conflict will be { add: [B, C],
// remove: [A] }. Also note that a conflict of the form { add: [A], remove: [] } is the
// same as non-conflict A.
pub removes: Vec<ConflictPart>,
pub adds: Vec<ConflictPart>,
}
impl Default for Conflict {
fn default() -> Self {
Conflict {
removes: Default::default(),
adds: Default::default(),
}
}
}
#[derive(Debug, Error, PartialEq, Eq)]
pub enum StoreError {
#[error("Object not found")]
NotFound,
#[error("Error: {0}")]
Other(String),
}
pub type StoreResult<T> = Result<T, StoreError>;
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum TreeValue {
Normal { id: FileId, executable: bool },
Symlink(SymlinkId),
Tree(TreeId),
GitSubmodule(CommitId),
Conflict(ConflictId),
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct TreeEntry<'a> {
name: &'a RepoPathComponent,
value: &'a TreeValue,
}
impl<'a> TreeEntry<'a> {
pub fn new(name: &'a RepoPathComponent, value: &'a TreeValue) -> Self {
TreeEntry { name, value }
}
pub fn name(&self) -> &'a RepoPathComponent {
self.name
}
pub fn value(&self) -> &'a TreeValue {
self.value
}
}
pub struct TreeEntriesNonRecursiveIter<'a> {
iter: std::collections::btree_map::Iter<'a, RepoPathComponent, TreeValue>,
}
impl<'a> Iterator for TreeEntriesNonRecursiveIter<'a> {
type Item = TreeEntry<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(|(name, value)| TreeEntry { name, value })
}
}
#[derive(Debug, Clone)]
pub struct Tree {
entries: BTreeMap<RepoPathComponent, TreeValue>,
}
impl Default for Tree {
fn default() -> Self {
Self {
entries: BTreeMap::new(),
}
}
}
impl Tree {
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn entries(&self) -> TreeEntriesNonRecursiveIter {
TreeEntriesNonRecursiveIter {
iter: self.entries.iter(),
}
}
pub fn set(&mut self, name: RepoPathComponent, value: TreeValue) {
self.entries.insert(name, value);
}
pub fn remove(&mut self, name: &RepoPathComponent) {
self.entries.remove(name);
}
pub fn entry(&self, name: &RepoPathComponent) -> Option<TreeEntry> {
self.entries
.get_key_value(name)
.map(|(name, value)| TreeEntry { name, value })
}
pub fn value(&self, name: &RepoPathComponent) -> Option<&TreeValue> {
self.entries.get(name)
}
}
pub trait Store: Send + Sync + Debug {
fn hash_length(&self) -> usize;
fn git_repo(&self) -> Option<git2::Repository>;
fn read_file(&self, path: &RepoPath, id: &FileId) -> StoreResult<Box<dyn Read>>;
fn write_file(&self, path: &RepoPath, contents: &mut dyn Read) -> StoreResult<FileId>;
fn read_symlink(&self, path: &RepoPath, id: &SymlinkId) -> StoreResult<String>;
fn write_symlink(&self, path: &RepoPath, target: &str) -> StoreResult<SymlinkId>;
fn empty_tree_id(&self) -> &TreeId;
fn read_tree(&self, path: &RepoPath, id: &TreeId) -> StoreResult<Tree>;
fn write_tree(&self, path: &RepoPath, contents: &Tree) -> StoreResult<TreeId>;
fn read_commit(&self, id: &CommitId) -> StoreResult<Commit>;
fn write_commit(&self, contents: &Commit) -> StoreResult<CommitId>;
// TODO: Pass in the paths here too even though they are unused, just like for
// files and trees?
fn read_conflict(&self, id: &ConflictId) -> StoreResult<Conflict>;
fn write_conflict(&self, contents: &Conflict) -> StoreResult<ConflictId>;
}

View file

@ -1,230 +0,0 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::sync::{Arc, RwLock, Weak};
use crate::commit::Commit;
use crate::git_store::GitStore;
use crate::local_store::LocalStore;
use crate::repo_path::RepoPath;
use crate::store;
use crate::store::{
ChangeId, CommitId, Conflict, ConflictId, FileId, MillisSinceEpoch, Signature, Store,
StoreResult, SymlinkId, Timestamp, TreeId,
};
use crate::tree::Tree;
use crate::tree_builder::TreeBuilder;
/// Wraps the low-level store and makes it return more convenient types. Also
/// adds the root commit and adds caching.
/// TODO: Come up with a better name, possibly by renaming the current Store
/// trait to something else.
#[derive(Debug)]
pub struct StoreWrapper {
weak_self: Option<Weak<StoreWrapper>>,
store: Box<dyn Store>,
root_commit_id: CommitId,
commit_cache: RwLock<HashMap<CommitId, Arc<store::Commit>>>,
tree_cache: RwLock<HashMap<(RepoPath, TreeId), Arc<store::Tree>>>,
}
impl StoreWrapper {
pub fn new(store: Box<dyn Store>) -> Arc<Self> {
let root_commit_id = CommitId(vec![0; store.hash_length()]);
let mut wrapper = Arc::new(StoreWrapper {
weak_self: None,
store,
root_commit_id,
commit_cache: Default::default(),
tree_cache: Default::default(),
});
let weak_self = Arc::downgrade(&wrapper);
let mut ref_mut = unsafe { Arc::get_mut_unchecked(&mut wrapper) };
ref_mut.weak_self = Some(weak_self);
wrapper
}
pub fn load_store(repo_path: &Path) -> Arc<StoreWrapper> {
let store_path = repo_path.join("store");
let store: Box<dyn Store>;
// TODO: Perhaps .jj/store should always be a directory. Then .jj/git would live
// inside that directory and this function would not need to know the repo path
// (only the store path). Maybe there would be a .jj/store/format file
// indicating which kind of store it is?
if store_path.is_dir() {
store = Box::new(LocalStore::load(store_path));
} else {
let mut store_file = File::open(store_path).unwrap();
let mut buf = Vec::new();
store_file.read_to_end(&mut buf).unwrap();
let contents = String::from_utf8(buf).unwrap();
assert!(contents.starts_with("git: "));
let git_store_path_str = contents[5..].to_string();
let git_store_path =
std::fs::canonicalize(repo_path.join(PathBuf::from(git_store_path_str))).unwrap();
store = Box::new(GitStore::load(&git_store_path));
}
StoreWrapper::new(store)
}
pub fn hash_length(&self) -> usize {
self.store.hash_length()
}
pub fn git_repo(&self) -> Option<git2::Repository> {
self.store.git_repo()
}
pub fn empty_tree_id(&self) -> &TreeId {
self.store.empty_tree_id()
}
pub fn root_commit_id(&self) -> &CommitId {
&self.root_commit_id
}
pub fn root_commit(&self) -> Commit {
self.get_commit(&self.root_commit_id).unwrap()
}
pub fn get_commit(&self, id: &CommitId) -> StoreResult<Commit> {
let data = self.get_store_commit(id)?;
Ok(Commit::new(
self.weak_self.as_ref().unwrap().upgrade().unwrap(),
id.clone(),
data,
))
}
fn make_root_commit(&self) -> store::Commit {
let timestamp = Timestamp {
timestamp: MillisSinceEpoch(0),
tz_offset: 0,
};
let signature = Signature {
name: String::new(),
email: String::new(),
timestamp,
};
let change_id = ChangeId(vec![0; 16]);
store::Commit {
parents: vec![],
predecessors: vec![],
root_tree: self.store.empty_tree_id().clone(),
change_id,
description: String::new(),
author: signature.clone(),
committer: signature,
is_open: false,
is_pruned: false,
}
}
fn get_store_commit(&self, id: &CommitId) -> StoreResult<Arc<store::Commit>> {
{
let read_locked_cached = self.commit_cache.read().unwrap();
if let Some(data) = read_locked_cached.get(id).cloned() {
return Ok(data);
}
}
let commit = if id == self.root_commit_id() {
self.make_root_commit()
} else {
self.store.read_commit(id)?
};
let data = Arc::new(commit);
let mut write_locked_cache = self.commit_cache.write().unwrap();
write_locked_cache.insert(id.clone(), data.clone());
Ok(data)
}
pub fn write_commit(&self, commit: store::Commit) -> Commit {
let commit_id = self.store.write_commit(&commit).unwrap();
let data = Arc::new(commit);
{
let mut write_locked_cache = self.commit_cache.write().unwrap();
write_locked_cache.insert(commit_id.clone(), data.clone());
}
let commit = Commit::new(
self.weak_self.as_ref().unwrap().upgrade().unwrap(),
commit_id,
data,
);
commit
}
pub fn get_tree(&self, dir: &RepoPath, id: &TreeId) -> StoreResult<Tree> {
let data = self.get_store_tree(dir, id)?;
Ok(Tree::new(
self.weak_self.as_ref().unwrap().upgrade().unwrap(),
dir.clone(),
id.clone(),
data,
))
}
fn get_store_tree(&self, dir: &RepoPath, id: &TreeId) -> StoreResult<Arc<store::Tree>> {
let key = (dir.clone(), id.clone());
{
let read_locked_cache = self.tree_cache.read().unwrap();
if let Some(data) = read_locked_cache.get(&key).cloned() {
return Ok(data);
}
}
let data = Arc::new(self.store.read_tree(dir, id)?);
let mut write_locked_cache = self.tree_cache.write().unwrap();
write_locked_cache.insert(key, data.clone());
Ok(data)
}
pub fn write_tree(&self, path: &RepoPath, contents: &store::Tree) -> StoreResult<TreeId> {
// TODO: This should also do caching like write_commit does.
self.store.write_tree(path, contents)
}
pub fn read_file(&self, path: &RepoPath, id: &FileId) -> StoreResult<Box<dyn Read>> {
self.store.read_file(path, id)
}
pub fn write_file(&self, path: &RepoPath, contents: &mut dyn Read) -> StoreResult<FileId> {
self.store.write_file(path, contents)
}
pub fn read_symlink(&self, path: &RepoPath, id: &SymlinkId) -> StoreResult<String> {
self.store.read_symlink(path, id)
}
pub fn write_symlink(&self, path: &RepoPath, contents: &str) -> StoreResult<SymlinkId> {
self.store.write_symlink(path, contents)
}
pub fn read_conflict(&self, id: &ConflictId) -> StoreResult<Conflict> {
self.store.read_conflict(id)
}
pub fn write_conflict(&self, contents: &Conflict) -> StoreResult<ConflictId> {
self.store.write_conflict(contents)
}
pub fn tree_builder(&self, base_tree_id: TreeId) -> TreeBuilder {
TreeBuilder::new(
self.weak_self.as_ref().unwrap().upgrade().unwrap(),
base_tree_id,
)
}
}

View file

@ -20,13 +20,13 @@ use std::sync::Arc;
use itertools::Itertools; use itertools::Itertools;
use tempfile::TempDir; use tempfile::TempDir;
use crate::backend::{FileId, TreeId, TreeValue};
use crate::commit::Commit; use crate::commit::Commit;
use crate::commit_builder::CommitBuilder; use crate::commit_builder::CommitBuilder;
use crate::repo::{MutableRepo, ReadonlyRepo}; use crate::repo::{MutableRepo, ReadonlyRepo};
use crate::repo_path::RepoPath; use crate::repo_path::RepoPath;
use crate::settings::UserSettings; use crate::settings::UserSettings;
use crate::store::{FileId, TreeId, TreeValue}; use crate::store::Store;
use crate::store_wrapper::StoreWrapper;
use crate::tree::Tree; use crate::tree::Tree;
use crate::tree_builder::TreeBuilder; use crate::tree_builder::TreeBuilder;
@ -62,7 +62,7 @@ pub fn init_repo(settings: &UserSettings, use_git: bool) -> (TempDir, Arc<Readon
(temp_dir, repo) (temp_dir, repo)
} }
pub fn write_file(store: &StoreWrapper, path: &RepoPath, contents: &str) -> FileId { pub fn write_file(store: &Store, path: &RepoPath, contents: &str) -> FileId {
store.write_file(path, &mut contents.as_bytes()).unwrap() store.write_file(path, &mut contents.as_bytes()).unwrap()
} }

View file

@ -15,13 +15,13 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use crate::backend::Timestamp;
use crate::evolution::ReadonlyEvolution; use crate::evolution::ReadonlyEvolution;
use crate::index::ReadonlyIndex; use crate::index::ReadonlyIndex;
use crate::op_store; use crate::op_store;
use crate::op_store::{OperationId, OperationMetadata}; use crate::op_store::{OperationId, OperationMetadata};
use crate::operation::Operation; use crate::operation::Operation;
use crate::repo::{MutableRepo, ReadonlyRepo, RepoLoader}; use crate::repo::{MutableRepo, ReadonlyRepo, RepoLoader};
use crate::store::Timestamp;
use crate::view::View; use crate::view::View;
use crate::working_copy::WorkingCopy; use crate::working_copy::WorkingCopy;

View file

@ -19,22 +19,22 @@ use std::iter::Peekable;
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
use crate::backend::{
BackendError, Conflict, ConflictId, ConflictPart, TreeEntriesNonRecursiveIter, TreeEntry,
TreeId, TreeValue,
};
use crate::files::MergeResult; use crate::files::MergeResult;
use crate::matchers::{EverythingMatcher, Matcher}; use crate::matchers::{EverythingMatcher, Matcher};
use crate::repo_path::{RepoPath, RepoPathComponent, RepoPathJoin}; use crate::repo_path::{RepoPath, RepoPathComponent, RepoPathJoin};
use crate::store::{ use crate::store::Store;
Conflict, ConflictId, ConflictPart, StoreError, TreeEntriesNonRecursiveIter, TreeEntry, TreeId, use crate::{backend, files};
TreeValue,
};
use crate::store_wrapper::StoreWrapper;
use crate::{files, store};
#[derive(Clone)] #[derive(Clone)]
pub struct Tree { pub struct Tree {
store: Arc<StoreWrapper>, store: Arc<Store>,
dir: RepoPath, dir: RepoPath,
id: TreeId, id: TreeId,
data: Arc<store::Tree>, data: Arc<backend::Tree>,
} }
impl Debug for Tree { impl Debug for Tree {
@ -60,12 +60,7 @@ impl DiffSummary {
} }
impl Tree { impl Tree {
pub fn new( pub fn new(store: Arc<Store>, dir: RepoPath, id: TreeId, data: Arc<backend::Tree>) -> Self {
store: Arc<StoreWrapper>,
dir: RepoPath,
id: TreeId,
data: Arc<store::Tree>,
) -> Self {
Tree { Tree {
store, store,
dir, dir,
@ -74,16 +69,16 @@ impl Tree {
} }
} }
pub fn null(store: Arc<StoreWrapper>, dir: RepoPath) -> Self { pub fn null(store: Arc<Store>, dir: RepoPath) -> Self {
Tree { Tree {
store, store,
dir, dir,
id: TreeId(vec![]), id: TreeId(vec![]),
data: Arc::new(store::Tree::default()), data: Arc::new(backend::Tree::default()),
} }
} }
pub fn store(&self) -> &Arc<StoreWrapper> { pub fn store(&self) -> &Arc<Store> {
&self.store &self.store
} }
@ -95,7 +90,7 @@ impl Tree {
&self.id &self.id
} }
pub fn data(&self) -> &store::Tree { pub fn data(&self) -> &backend::Tree {
&self.data &self.data
} }
@ -496,7 +491,7 @@ pub fn merge_trees(
side1_tree: &Tree, side1_tree: &Tree,
base_tree: &Tree, base_tree: &Tree,
side2_tree: &Tree, side2_tree: &Tree,
) -> Result<TreeId, StoreError> { ) -> Result<TreeId, BackendError> {
let store = base_tree.store().as_ref(); let store = base_tree.store().as_ref();
let dir = base_tree.dir(); let dir = base_tree.dir();
assert_eq!(side1_tree.dir(), dir); assert_eq!(side1_tree.dir(), dir);
@ -539,13 +534,13 @@ pub fn merge_trees(
} }
fn merge_tree_value( fn merge_tree_value(
store: &StoreWrapper, store: &Store,
dir: &RepoPath, dir: &RepoPath,
basename: &RepoPathComponent, basename: &RepoPathComponent,
maybe_base: Option<&TreeValue>, maybe_base: Option<&TreeValue>,
maybe_side1: Option<&TreeValue>, maybe_side1: Option<&TreeValue>,
maybe_side2: Option<&TreeValue>, maybe_side2: Option<&TreeValue>,
) -> Result<Option<TreeValue>, StoreError> { ) -> Result<Option<TreeValue>, BackendError> {
// Resolve non-trivial conflicts: // Resolve non-trivial conflicts:
// * resolve tree conflicts by recursing // * resolve tree conflicts by recursing
// * try to resolve file conflicts by merging the file contents // * try to resolve file conflicts by merging the file contents
@ -646,10 +641,7 @@ fn merge_tree_value(
}) })
} }
fn conflict_part_to_conflict( fn conflict_part_to_conflict(store: &Store, part: &ConflictPart) -> Result<Conflict, BackendError> {
store: &StoreWrapper,
part: &ConflictPart,
) -> Result<Conflict, StoreError> {
match &part.value { match &part.value {
TreeValue::Conflict(id) => { TreeValue::Conflict(id) => {
let conflict = store.read_conflict(id)?; let conflict = store.read_conflict(id)?;
@ -665,9 +657,9 @@ fn conflict_part_to_conflict(
} }
fn simplify_conflict( fn simplify_conflict(
store: &StoreWrapper, store: &Store,
conflict: &Conflict, conflict: &Conflict,
) -> Result<Option<TreeValue>, StoreError> { ) -> Result<Option<TreeValue>, BackendError> {
// Important cases to simplify: // Important cases to simplify:
// //
// D // D

View file

@ -15,10 +15,10 @@
use std::collections::{BTreeMap, HashSet}; use std::collections::{BTreeMap, HashSet};
use std::sync::Arc; use std::sync::Arc;
use crate::backend;
use crate::backend::{TreeId, TreeValue};
use crate::repo_path::{RepoPath, RepoPathJoin}; use crate::repo_path::{RepoPath, RepoPathJoin};
use crate::store; use crate::store::Store;
use crate::store::{TreeId, TreeValue};
use crate::store_wrapper::StoreWrapper;
use crate::tree::Tree; use crate::tree::Tree;
#[derive(Debug)] #[derive(Debug)]
@ -29,13 +29,13 @@ enum Override {
#[derive(Debug)] #[derive(Debug)]
pub struct TreeBuilder { pub struct TreeBuilder {
store: Arc<StoreWrapper>, store: Arc<Store>,
base_tree_id: TreeId, base_tree_id: TreeId,
overrides: BTreeMap<RepoPath, Override>, overrides: BTreeMap<RepoPath, Override>,
} }
impl TreeBuilder { impl TreeBuilder {
pub fn new(store: Arc<StoreWrapper>, base_tree_id: TreeId) -> TreeBuilder { pub fn new(store: Arc<Store>, base_tree_id: TreeId) -> TreeBuilder {
let overrides = BTreeMap::new(); let overrides = BTreeMap::new();
TreeBuilder { TreeBuilder {
store, store,
@ -44,7 +44,7 @@ impl TreeBuilder {
} }
} }
pub fn repo(&self) -> &StoreWrapper { pub fn repo(&self) -> &Store {
self.store.as_ref() self.store.as_ref()
} }
@ -108,7 +108,7 @@ impl TreeBuilder {
} }
} }
fn get_base_trees(&mut self) -> BTreeMap<RepoPath, store::Tree> { fn get_base_trees(&mut self) -> BTreeMap<RepoPath, backend::Tree> {
let mut tree_cache = BTreeMap::new(); let mut tree_cache = BTreeMap::new();
let mut base_trees = BTreeMap::new(); let mut base_trees = BTreeMap::new();
let store = self.store.clone(); let store = self.store.clone();

View file

@ -14,11 +14,11 @@
use std::collections::{BTreeMap, HashSet}; use std::collections::{BTreeMap, HashSet};
use crate::backend::CommitId;
use crate::index::IndexRef; use crate::index::IndexRef;
use crate::op_store; use crate::op_store;
use crate::op_store::{BranchTarget, RefTarget}; use crate::op_store::{BranchTarget, RefTarget};
use crate::refs::merge_ref_targets; use crate::refs::merge_ref_targets;
use crate::store::CommitId;
#[derive(PartialEq, Eq, Clone, Hash, Debug)] #[derive(PartialEq, Eq, Clone, Hash, Debug)]
pub enum RefName { pub enum RefName {

View file

@ -31,13 +31,15 @@ use protobuf::Message;
use tempfile::NamedTempFile; use tempfile::NamedTempFile;
use thiserror::Error; use thiserror::Error;
use crate::backend::{
BackendError, CommitId, FileId, MillisSinceEpoch, SymlinkId, TreeId, TreeValue,
};
use crate::commit::Commit; use crate::commit::Commit;
use crate::gitignore::GitIgnoreFile; use crate::gitignore::GitIgnoreFile;
use crate::lock::FileLock; use crate::lock::FileLock;
use crate::matchers::EverythingMatcher; use crate::matchers::EverythingMatcher;
use crate::repo_path::{RepoPath, RepoPathComponent, RepoPathJoin}; use crate::repo_path::{RepoPath, RepoPathComponent, RepoPathJoin};
use crate::store::{CommitId, FileId, MillisSinceEpoch, StoreError, SymlinkId, TreeId, TreeValue}; use crate::store::Store;
use crate::store_wrapper::StoreWrapper;
use crate::tree::Diff; use crate::tree::Diff;
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
@ -76,7 +78,7 @@ impl FileState {
} }
pub struct TreeState { pub struct TreeState {
store: Arc<StoreWrapper>, store: Arc<Store>,
working_copy_path: PathBuf, working_copy_path: PathBuf,
state_path: PathBuf, state_path: PathBuf,
tree_id: TreeId, tree_id: TreeId,
@ -146,7 +148,7 @@ pub enum CheckoutError {
#[error("Concurrent checkout")] #[error("Concurrent checkout")]
ConcurrentCheckout, ConcurrentCheckout,
#[error("Internal error: {0:?}")] #[error("Internal error: {0:?}")]
InternalStoreError(StoreError), InternalBackendError(BackendError),
} }
impl TreeState { impl TreeState {
@ -158,21 +160,13 @@ impl TreeState {
&self.file_states &self.file_states
} }
pub fn init( pub fn init(store: Arc<Store>, working_copy_path: PathBuf, state_path: PathBuf) -> TreeState {
store: Arc<StoreWrapper>,
working_copy_path: PathBuf,
state_path: PathBuf,
) -> TreeState {
let mut wc = TreeState::empty(store, working_copy_path, state_path); let mut wc = TreeState::empty(store, working_copy_path, state_path);
wc.save(); wc.save();
wc wc
} }
fn empty( fn empty(store: Arc<Store>, working_copy_path: PathBuf, state_path: PathBuf) -> TreeState {
store: Arc<StoreWrapper>,
working_copy_path: PathBuf,
state_path: PathBuf,
) -> TreeState {
let tree_id = store.empty_tree_id().clone(); let tree_id = store.empty_tree_id().clone();
// Canonicalize the working copy path because "repo/." makes libgit2 think that // Canonicalize the working copy path because "repo/." makes libgit2 think that
// everything should be ignored // everything should be ignored
@ -186,11 +180,7 @@ impl TreeState {
} }
} }
pub fn load( pub fn load(store: Arc<Store>, working_copy_path: PathBuf, state_path: PathBuf) -> TreeState {
store: Arc<StoreWrapper>,
working_copy_path: PathBuf,
state_path: PathBuf,
) -> TreeState {
let maybe_file = File::open(state_path.join("tree_state")); let maybe_file = File::open(state_path.join("tree_state"));
let file = match maybe_file { let file = match maybe_file {
Err(ref err) if err.kind() == std::io::ErrorKind::NotFound => { Err(ref err) if err.kind() == std::io::ErrorKind::NotFound => {
@ -481,15 +471,15 @@ impl TreeState {
.store .store
.get_tree(&RepoPath::root(), &self.tree_id) .get_tree(&RepoPath::root(), &self.tree_id)
.map_err(|err| match err { .map_err(|err| match err {
StoreError::NotFound => CheckoutError::SourceNotFound, BackendError::NotFound => CheckoutError::SourceNotFound,
other => CheckoutError::InternalStoreError(other), other => CheckoutError::InternalBackendError(other),
})?; })?;
let new_tree = let new_tree =
self.store self.store
.get_tree(&RepoPath::root(), &tree_id) .get_tree(&RepoPath::root(), &tree_id)
.map_err(|err| match err { .map_err(|err| match err {
StoreError::NotFound => CheckoutError::TargetNotFound, BackendError::NotFound => CheckoutError::TargetNotFound,
other => CheckoutError::InternalStoreError(other), other => CheckoutError::InternalBackendError(other),
})?; })?;
let mut stats = CheckoutStats { let mut stats = CheckoutStats {
@ -587,7 +577,7 @@ impl TreeState {
} }
pub struct WorkingCopy { pub struct WorkingCopy {
store: Arc<StoreWrapper>, store: Arc<Store>,
working_copy_path: PathBuf, working_copy_path: PathBuf,
state_path: PathBuf, state_path: PathBuf,
commit_id: RefCell<Option<CommitId>>, commit_id: RefCell<Option<CommitId>>,
@ -597,11 +587,7 @@ pub struct WorkingCopy {
} }
impl WorkingCopy { impl WorkingCopy {
pub fn init( pub fn init(store: Arc<Store>, working_copy_path: PathBuf, state_path: PathBuf) -> WorkingCopy {
store: Arc<StoreWrapper>,
working_copy_path: PathBuf,
state_path: PathBuf,
) -> WorkingCopy {
// Leave the commit_id empty so a subsequent call to check out the root revision // Leave the commit_id empty so a subsequent call to check out the root revision
// will have an effect. // will have an effect.
let proto = crate::protos::working_copy::Checkout::new(); let proto = crate::protos::working_copy::Checkout::new();
@ -621,11 +607,7 @@ impl WorkingCopy {
} }
} }
pub fn load( pub fn load(store: Arc<Store>, working_copy_path: PathBuf, state_path: PathBuf) -> WorkingCopy {
store: Arc<StoreWrapper>,
working_copy_path: PathBuf,
state_path: PathBuf,
) -> WorkingCopy {
WorkingCopy { WorkingCopy {
store, store,
working_copy_path, working_copy_path,

View file

@ -88,8 +88,8 @@ fn merge_directories(left: &Path, base: &Path, right: &Path, output: &Path) {
} }
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_bad_locking_children(use_git: bool) { fn test_bad_locking_children(use_git: bool) {
// Test that two new commits created on separate machines are both visible (not // Test that two new commits created on separate machines are both visible (not
// lost due to lack of locking) // lost due to lack of locking)
@ -139,8 +139,8 @@ fn test_bad_locking_children(use_git: bool) {
assert_eq!(op.parents.len(), 2); assert_eq!(op.parents.len(), 2);
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_bad_locking_interrupted(use_git: bool) { fn test_bad_locking_interrupted(use_git: bool) {
// Test that an interrupted update of the op-heads resulting in on op-head // Test that an interrupted update of the op-heads resulting in on op-head
// that's a descendant of the other is resolved without creating a new // that's a descendant of the other is resolved without creating a new

View file

@ -20,8 +20,8 @@ use jujutsu_lib::testutils;
use jujutsu_lib::tree::DiffSummary; use jujutsu_lib::tree::DiffSummary;
use test_case::test_case; use test_case::test_case;
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_initial(use_git: bool) { fn test_initial(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -64,8 +64,8 @@ fn test_initial(use_git: bool) {
); );
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_rewrite(use_git: bool) { fn test_rewrite(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);

View file

@ -36,8 +36,8 @@ fn count_non_merge_operations(repo: &ReadonlyRepo) -> usize {
num_ops num_ops
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_commit_parallel(use_git: bool) { fn test_commit_parallel(use_git: bool) {
// This loads a Repo instance and creates and commits many concurrent // This loads a Repo instance and creates and commits many concurrent
// transactions from it. It then reloads the repo. That should merge all the // transactions from it. It then reloads the repo. That should merge all the
@ -70,8 +70,8 @@ fn test_commit_parallel(use_git: bool) {
assert_eq!(count_non_merge_operations(&repo), num_threads + 1); assert_eq!(count_non_merge_operations(&repo), num_threads + 1);
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_commit_parallel_instances(use_git: bool) { fn test_commit_parallel_instances(use_git: bool) {
// Like the test above but creates a new repo instance for every thread, which // Like the test above but creates a new repo instance for every thread, which
// makes it behave very similar to separate processes. // makes it behave very similar to separate processes.

View file

@ -19,8 +19,8 @@ use jujutsu_lib::tree::DiffSummary;
use maplit::hashset; use maplit::hashset;
use test_case::test_case; use test_case::test_case;
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_types(use_git: bool) { fn test_types(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -58,8 +58,8 @@ fn test_types(use_git: bool) {
); );
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_tree_file_transition(use_git: bool) { fn test_tree_file_transition(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -88,8 +88,8 @@ fn test_tree_file_transition(use_git: bool) {
); );
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_sorting(use_git: bool) { fn test_sorting(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -153,8 +153,8 @@ fn test_sorting(use_git: bool) {
); );
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_matcher_dir_file_transition(use_git: bool) { fn test_matcher_dir_file_transition(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -220,8 +220,8 @@ fn test_matcher_dir_file_transition(use_git: bool) {
); );
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_matcher_normal_cases(use_git: bool) { fn test_matcher_normal_cases(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);

View file

@ -33,8 +33,8 @@ fn child_commit(settings: &UserSettings, repo: &ReadonlyRepo, commit: &Commit) -
testutils::create_random_commit(settings, repo).set_parents(vec![commit.id().clone()]) testutils::create_random_commit(settings, repo).set_parents(vec![commit.id().clone()])
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_obsolete_and_orphan(use_git: bool) { fn test_obsolete_and_orphan(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -80,8 +80,8 @@ fn test_obsolete_and_orphan(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_divergent(use_git: bool) { fn test_divergent(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -107,8 +107,8 @@ fn test_divergent(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_divergent_pruned(use_git: bool) { fn test_divergent_pruned(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -134,8 +134,8 @@ fn test_divergent_pruned(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_divergent_duplicate(use_git: bool) { fn test_divergent_duplicate(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -163,8 +163,8 @@ fn test_divergent_duplicate(use_git: bool) {
// TODO: Create a #[repo_test] proc macro that injects the `settings` and `repo` // TODO: Create a #[repo_test] proc macro that injects the `settings` and `repo`
// variables into the test function // variables into the test function
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_new_parent_rewritten(use_git: bool) { fn test_new_parent_rewritten(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -187,8 +187,8 @@ fn test_new_parent_rewritten(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_new_parent_cherry_picked(use_git: bool) { fn test_new_parent_cherry_picked(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -210,8 +210,8 @@ fn test_new_parent_cherry_picked(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_new_parent_is_pruned(use_git: bool) { fn test_new_parent_is_pruned(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -237,8 +237,8 @@ fn test_new_parent_is_pruned(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_new_parent_divergent(use_git: bool) { fn test_new_parent_divergent(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -275,8 +275,8 @@ fn test_new_parent_divergent(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_new_parent_divergent_one_not_pruned(use_git: bool) { fn test_new_parent_divergent_one_not_pruned(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -319,8 +319,8 @@ fn test_new_parent_divergent_one_not_pruned(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_new_parent_divergent_all_pruned(use_git: bool) { fn test_new_parent_divergent_all_pruned(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -365,8 +365,8 @@ fn test_new_parent_divergent_all_pruned(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_new_parent_split(use_git: bool) { fn test_new_parent_split(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -398,8 +398,8 @@ fn test_new_parent_split(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_new_parent_split_pruned_descendant(use_git: bool) { fn test_new_parent_split_pruned_descendant(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -435,8 +435,8 @@ fn test_new_parent_split_pruned_descendant(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_new_parent_split_forked(use_git: bool) { fn test_new_parent_split_forked(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -474,8 +474,8 @@ fn test_new_parent_split_forked(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_new_parent_split_forked_pruned(use_git: bool) { fn test_new_parent_split_forked_pruned(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -511,8 +511,8 @@ fn test_new_parent_split_forked_pruned(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_evolve_orphan(use_git: bool) { fn test_evolve_orphan(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -554,8 +554,8 @@ fn test_evolve_orphan(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
/// When evolving a merge commit, the new commit should not have a parent that /// When evolving a merge commit, the new commit should not have a parent that
/// is an ancestor of another parent. /// is an ancestor of another parent.
fn test_evolve_orphan_merge_ancestor_of_other_parent(use_git: bool) { fn test_evolve_orphan_merge_ancestor_of_other_parent(use_git: bool) {
@ -589,8 +589,8 @@ fn test_evolve_orphan_merge_ancestor_of_other_parent(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evolve_pruned_orphan(use_git: bool) { fn test_evolve_pruned_orphan(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -625,8 +625,8 @@ fn test_evolve_pruned_orphan(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_evolve_multiple_orphans(use_git: bool) { fn test_evolve_multiple_orphans(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -679,8 +679,8 @@ fn test_evolve_multiple_orphans(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_evolve_divergent(use_git: bool) { fn test_evolve_divergent(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);

View file

@ -16,12 +16,12 @@ use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use git2::Oid; use git2::Oid;
use jujutsu_lib::backend::CommitId;
use jujutsu_lib::commit::Commit; use jujutsu_lib::commit::Commit;
use jujutsu_lib::git::{GitFetchError, GitPushError, GitRefUpdate}; use jujutsu_lib::git::{GitFetchError, GitPushError, GitRefUpdate};
use jujutsu_lib::op_store::{BranchTarget, RefTarget}; use jujutsu_lib::op_store::{BranchTarget, RefTarget};
use jujutsu_lib::repo::ReadonlyRepo; use jujutsu_lib::repo::ReadonlyRepo;
use jujutsu_lib::settings::UserSettings; use jujutsu_lib::settings::UserSettings;
use jujutsu_lib::store::CommitId;
use jujutsu_lib::testutils::create_random_commit; use jujutsu_lib::testutils::create_random_commit;
use jujutsu_lib::{git, testutils}; use jujutsu_lib::{git, testutils};
use maplit::{btreemap, hashset}; use maplit::{btreemap, hashset};

View file

@ -14,12 +14,12 @@
use std::sync::Arc; use std::sync::Arc;
use jujutsu_lib::backend::CommitId;
use jujutsu_lib::commit::Commit; use jujutsu_lib::commit::Commit;
use jujutsu_lib::commit_builder::CommitBuilder; use jujutsu_lib::commit_builder::CommitBuilder;
use jujutsu_lib::index::IndexRef; use jujutsu_lib::index::IndexRef;
use jujutsu_lib::repo::ReadonlyRepo; use jujutsu_lib::repo::ReadonlyRepo;
use jujutsu_lib::settings::UserSettings; use jujutsu_lib::settings::UserSettings;
use jujutsu_lib::store::CommitId;
use jujutsu_lib::testutils; use jujutsu_lib::testutils;
use jujutsu_lib::testutils::{create_random_commit, CommitGraphBuilder}; use jujutsu_lib::testutils::{create_random_commit, CommitGraphBuilder};
use test_case::test_case; use test_case::test_case;
@ -38,8 +38,8 @@ fn generation_number<'a>(index: impl Into<IndexRef<'a>>, commit_id: &CommitId) -
.generation_number() .generation_number()
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_index_commits_empty_repo(use_git: bool) { fn test_index_commits_empty_repo(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -62,8 +62,8 @@ fn test_index_commits_empty_repo(use_git: bool) {
); );
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_index_commits_standard_cases(use_git: bool) { fn test_index_commits_standard_cases(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -132,8 +132,8 @@ fn test_index_commits_standard_cases(use_git: bool) {
assert!(index.is_ancestor(commit_a.id(), commit_h.id())); assert!(index.is_ancestor(commit_a.id(), commit_h.id()));
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_index_commits_criss_cross(use_git: bool) { fn test_index_commits_criss_cross(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -231,8 +231,8 @@ fn test_index_commits_criss_cross(use_git: bool) {
); );
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_index_commits_previous_operations(use_git: bool) { fn test_index_commits_previous_operations(use_git: bool) {
// Test that commits visible only in previous operations are indexed. // Test that commits visible only in previous operations are indexed.
let settings = testutils::user_settings(); let settings = testutils::user_settings();
@ -284,8 +284,8 @@ fn test_index_commits_previous_operations(use_git: bool) {
assert_eq!(generation_number(index.as_ref(), commit_c.id()), 3); assert_eq!(generation_number(index.as_ref(), commit_c.id()), 3);
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_index_commits_incremental(use_git: bool) { fn test_index_commits_incremental(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, mut repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, mut repo) = testutils::init_repo(&settings, use_git);
@ -333,8 +333,8 @@ fn test_index_commits_incremental(use_git: bool) {
assert_eq!(generation_number(index.as_ref(), commit_c.id()), 3); assert_eq!(generation_number(index.as_ref(), commit_c.id()), 3);
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_index_commits_incremental_empty_transaction(use_git: bool) { fn test_index_commits_incremental_empty_transaction(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, mut repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, mut repo) = testutils::init_repo(&settings, use_git);
@ -375,8 +375,8 @@ fn test_index_commits_incremental_empty_transaction(use_git: bool) {
assert_eq!(generation_number(index.as_ref(), commit_a.id()), 1); assert_eq!(generation_number(index.as_ref(), commit_a.id()), 1);
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_index_commits_incremental_already_indexed(use_git: bool) { fn test_index_commits_incremental_already_indexed(use_git: bool) {
// Tests that trying to add a commit that's already been added is a no-op. // Tests that trying to add a commit that's already been added is a no-op.
let settings = testutils::user_settings(); let settings = testutils::user_settings();
@ -424,8 +424,8 @@ fn commits_by_level(repo: &ReadonlyRepo) -> Vec<u32> {
.collect() .collect()
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_index_commits_incremental_squashed(use_git: bool) { fn test_index_commits_incremental_squashed(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();

View file

@ -68,8 +68,8 @@ fn test_init_external_git() {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_init_no_config_set(use_git: bool) { fn test_init_no_config_set(use_git: bool) {
// Test that we can create a repo without setting any config // Test that we can create a repo without setting any config
let settings = UserSettings::from_config(config::Config::new()); let settings = UserSettings::from_config(config::Config::new());
@ -90,8 +90,8 @@ fn test_init_no_config_set(use_git: bool) {
); );
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_init_checkout(use_git: bool) { fn test_init_checkout(use_git: bool) {
// Test the contents of the checkout after init // Test the contents of the checkout after init
let settings = testutils::user_settings(); let settings = testutils::user_settings();

View file

@ -26,8 +26,8 @@ fn test_load_bad_path() {
assert_eq!(result.err(), Some(RepoLoadError::NoRepoHere(wc_path))); assert_eq!(result.err(), Some(RepoLoadError::NoRepoHere(wc_path)));
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_load_from_subdir(use_git: bool) { fn test_load_from_subdir(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -41,8 +41,8 @@ fn test_load_from_subdir(use_git: bool) {
assert_eq!(same_repo.working_copy_path(), repo.working_copy_path()); assert_eq!(same_repo.working_copy_path(), repo.working_copy_path());
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_load_at_operation(use_git: bool) { fn test_load_at_operation(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);

View file

@ -13,14 +13,14 @@
// limitations under the License. // limitations under the License.
use itertools::Itertools; use itertools::Itertools;
use jujutsu_lib::backend::{ConflictPart, TreeValue};
use jujutsu_lib::repo_path::{RepoPath, RepoPathComponent}; use jujutsu_lib::repo_path::{RepoPath, RepoPathComponent};
use jujutsu_lib::store::{ConflictPart, TreeValue};
use jujutsu_lib::tree::Tree; use jujutsu_lib::tree::Tree;
use jujutsu_lib::{testutils, tree}; use jujutsu_lib::{testutils, tree};
use test_case::test_case; use test_case::test_case;
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_same_type(use_git: bool) { fn test_same_type(use_git: bool) {
// Tests all possible cases where the entry type is unchanged, specifically // Tests all possible cases where the entry type is unchanged, specifically
// using only normal files in all trees (no symlinks, no trees, etc.). // using only normal files in all trees (no symlinks, no trees, etc.).
@ -219,8 +219,8 @@ fn test_same_type(use_git: bool) {
}; };
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_subtrees(use_git: bool) { fn test_subtrees(use_git: bool) {
// Tests that subtrees are merged. // Tests that subtrees are merged.
@ -275,8 +275,8 @@ fn test_subtrees(use_git: bool) {
assert_eq!(entries, expected_entries); assert_eq!(entries, expected_entries);
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_subtree_becomes_empty(use_git: bool) { fn test_subtree_becomes_empty(use_git: bool) {
// Tests that subtrees that become empty are removed from the parent tree. // Tests that subtrees that become empty are removed from the parent tree.
@ -306,8 +306,8 @@ fn test_subtree_becomes_empty(use_git: bool) {
assert_eq!(merged_tree.id(), store.empty_tree_id()); assert_eq!(merged_tree.id(), store.empty_tree_id());
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_types(use_git: bool) { fn test_types(use_git: bool) {
// Tests conflicts between different types. This is mostly to test that the // Tests conflicts between different types. This is mostly to test that the
// conflicts survive the roundtrip to the store. // conflicts survive the roundtrip to the store.
@ -433,8 +433,8 @@ fn test_types(use_git: bool) {
}; };
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_simplify_conflict(use_git: bool) { fn test_simplify_conflict(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);

View file

@ -14,11 +14,11 @@
use std::sync::Arc; use std::sync::Arc;
use jujutsu_lib::backend::{Conflict, ConflictId, ConflictPart, TreeValue};
use jujutsu_lib::commit_builder::CommitBuilder; use jujutsu_lib::commit_builder::CommitBuilder;
use jujutsu_lib::op_store::RefTarget; use jujutsu_lib::op_store::RefTarget;
use jujutsu_lib::repo_path::RepoPath; use jujutsu_lib::repo_path::RepoPath;
use jujutsu_lib::store::{Conflict, ConflictId, ConflictPart, TreeValue}; use jujutsu_lib::store::Store;
use jujutsu_lib::store_wrapper::StoreWrapper;
use jujutsu_lib::testutils; use jujutsu_lib::testutils;
use jujutsu_lib::testutils::CommitGraphBuilder; use jujutsu_lib::testutils::CommitGraphBuilder;
use test_case::test_case; use test_case::test_case;
@ -26,8 +26,8 @@ use test_case::test_case;
// TODO Many of the tests here are not run with Git because they end up creating // TODO Many of the tests here are not run with Git because they end up creating
// two commits with the same contents. // two commits with the same contents.
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_checkout_open(use_git: bool) { fn test_checkout_open(use_git: bool) {
// Test that MutableRepo::check_out() uses the requested commit if it's open // Test that MutableRepo::check_out() uses the requested commit if it's open
let settings = testutils::user_settings(); let settings = testutils::user_settings();
@ -46,8 +46,8 @@ fn test_checkout_open(use_git: bool) {
assert_eq!(repo.view().checkout(), actual_checkout.id()); assert_eq!(repo.view().checkout(), actual_checkout.id());
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_checkout_closed(use_git: bool) { fn test_checkout_closed(use_git: bool) {
// Test that MutableRepo::check_out() creates a child if the requested commit is // Test that MutableRepo::check_out() creates a child if the requested commit is
// closed // closed
@ -69,8 +69,8 @@ fn test_checkout_closed(use_git: bool) {
assert_eq!(repo.view().checkout(), actual_checkout.id()); assert_eq!(repo.view().checkout(), actual_checkout.id());
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_checkout_open_with_conflict(use_git: bool) { fn test_checkout_open_with_conflict(use_git: bool) {
// Test that MutableRepo::check_out() creates a child if the requested // Test that MutableRepo::check_out() creates a child if the requested
// commit is open and has conflicts // commit is open and has conflicts
@ -108,8 +108,8 @@ fn test_checkout_open_with_conflict(use_git: bool) {
assert_eq!(repo.view().checkout(), actual_checkout.id()); assert_eq!(repo.view().checkout(), actual_checkout.id());
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_checkout_closed_with_conflict(use_git: bool) { fn test_checkout_closed_with_conflict(use_git: bool) {
// Test that MutableRepo::check_out() creates a child if the requested commit is // Test that MutableRepo::check_out() creates a child if the requested commit is
// closed and has conflicts // closed and has conflicts
@ -147,7 +147,7 @@ fn test_checkout_closed_with_conflict(use_git: bool) {
assert_eq!(repo.view().checkout(), actual_checkout.id()); assert_eq!(repo.view().checkout(), actual_checkout.id());
} }
fn write_conflict(store: &Arc<StoreWrapper>, file_path: &RepoPath) -> ConflictId { fn write_conflict(store: &Arc<Store>, file_path: &RepoPath) -> ConflictId {
let file_id1 = testutils::write_file(store, file_path, "a\n"); let file_id1 = testutils::write_file(store, file_path, "a\n");
let file_id2 = testutils::write_file(store, file_path, "b\n"); let file_id2 = testutils::write_file(store, file_path, "b\n");
let file_id3 = testutils::write_file(store, file_path, "c\n"); let file_id3 = testutils::write_file(store, file_path, "c\n");
@ -176,8 +176,8 @@ fn write_conflict(store: &Arc<StoreWrapper>, file_path: &RepoPath) -> ConflictId
store.write_conflict(&conflict).unwrap() store.write_conflict(&conflict).unwrap()
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_checkout_previous_not_empty(use_git: bool) { fn test_checkout_previous_not_empty(use_git: bool) {
// Test that MutableRepo::check_out() does not usually prune the previous // Test that MutableRepo::check_out() does not usually prune the previous
// commit. // commit.
@ -202,8 +202,8 @@ fn test_checkout_previous_not_empty(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_checkout_previous_empty(use_git: bool) { fn test_checkout_previous_empty(use_git: bool) {
// Test that MutableRepo::check_out() prunes the previous commit if it was // Test that MutableRepo::check_out() prunes the previous commit if it was
// empty. // empty.
@ -232,8 +232,8 @@ fn test_checkout_previous_empty(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_checkout_previous_empty_and_obsolete(use_git: bool) { fn test_checkout_previous_empty_and_obsolete(use_git: bool) {
// Test that MutableRepo::check_out() does not unnecessarily prune the previous // Test that MutableRepo::check_out() does not unnecessarily prune the previous
// commit if it was empty but already obsolete. // commit if it was empty but already obsolete.
@ -266,8 +266,8 @@ fn test_checkout_previous_empty_and_obsolete(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_checkout_previous_empty_and_pruned(use_git: bool) { fn test_checkout_previous_empty_and_pruned(use_git: bool) {
// Test that MutableRepo::check_out() does not unnecessarily prune the previous // Test that MutableRepo::check_out() does not unnecessarily prune the previous
// commit if it was empty but already obsolete. // commit if it was empty but already obsolete.
@ -296,8 +296,8 @@ fn test_checkout_previous_empty_and_pruned(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_add_head_success(use_git: bool) { fn test_add_head_success(use_git: bool) {
// Test that MutableRepo::add_head() adds the head, and that it's still there // Test that MutableRepo::add_head() adds the head, and that it's still there
// after commit. It should also be indexed. // after commit. It should also be indexed.
@ -330,8 +330,8 @@ fn test_add_head_success(use_git: bool) {
assert_eq!(index_stats.max_generation_number, 1); assert_eq!(index_stats.max_generation_number, 1);
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_add_head_ancestor(use_git: bool) { fn test_add_head_ancestor(use_git: bool) {
// Test that MutableRepo::add_head() does not add a head if it's an ancestor of // Test that MutableRepo::add_head() does not add a head if it's an ancestor of
// an existing head. // an existing head.
@ -360,8 +360,8 @@ fn test_add_head_ancestor(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_add_head_not_immediate_child(use_git: bool) { fn test_add_head_not_immediate_child(use_git: bool) {
// Test that MutableRepo::add_head() can be used for adding a head that is not // Test that MutableRepo::add_head() can be used for adding a head that is not
// an immediate child of a current head. // an immediate child of a current head.
@ -405,8 +405,8 @@ fn test_add_head_not_immediate_child(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_remove_head(use_git: bool) { fn test_remove_head(use_git: bool) {
// Test that MutableRepo::remove_head() removes the head, and that it's still // Test that MutableRepo::remove_head() removes the head, and that it's still
// removed after commit. It should remain in the index, since we otherwise would // removed after commit. It should remain in the index, since we otherwise would
@ -446,8 +446,8 @@ fn test_remove_head(use_git: bool) {
assert!(repo.index().has_id(commit3.id())); assert!(repo.index().has_id(commit3.id()));
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_remove_head_ancestor_git_ref(use_git: bool) { fn test_remove_head_ancestor_git_ref(use_git: bool) {
// Test that MutableRepo::remove_head() does not leave the view with a git ref // Test that MutableRepo::remove_head() does not leave the view with a git ref
// pointing to a commit that's not reachable by any head. // pointing to a commit that's not reachable by any head.
@ -490,8 +490,8 @@ fn test_remove_head_ancestor_git_ref(use_git: bool) {
assert!(!heads.contains(commit1.id())); assert!(!heads.contains(commit1.id()));
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_add_public_head(use_git: bool) { fn test_add_public_head(use_git: bool) {
// Test that MutableRepo::add_public_head() adds the head, and that it's still // Test that MutableRepo::add_public_head() adds the head, and that it's still
// there after commit. // there after commit.
@ -511,8 +511,8 @@ fn test_add_public_head(use_git: bool) {
assert!(repo.view().public_heads().contains(commit1.id())); assert!(repo.view().public_heads().contains(commit1.id()));
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_add_public_head_ancestor(use_git: bool) { fn test_add_public_head_ancestor(use_git: bool) {
// Test that MutableRepo::add_public_head() does not add a public head if it's // Test that MutableRepo::add_public_head() does not add a public head if it's
// an ancestor of an existing public head. // an ancestor of an existing public head.
@ -535,8 +535,8 @@ fn test_add_public_head_ancestor(use_git: bool) {
assert!(!repo.view().public_heads().contains(commit1.id())); assert!(!repo.view().public_heads().contains(commit1.id()));
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
// #[test_case(true ; "git store")] // #[test_case(true ; "git backend")]
fn test_remove_public_head(use_git: bool) { fn test_remove_public_head(use_git: bool) {
// Test that MutableRepo::remove_public_head() removes the head, and that it's // Test that MutableRepo::remove_public_head() removes the head, and that it's
// still removed after commit. // still removed after commit.

View file

@ -14,9 +14,9 @@
use std::path::Path; use std::path::Path;
use jujutsu_lib::backend::CommitId;
use jujutsu_lib::commit_builder::CommitBuilder; use jujutsu_lib::commit_builder::CommitBuilder;
use jujutsu_lib::repo::RepoRef; use jujutsu_lib::repo::RepoRef;
use jujutsu_lib::store::CommitId;
use jujutsu_lib::testutils; use jujutsu_lib::testutils;
use test_case::test_case; use test_case::test_case;
@ -27,8 +27,8 @@ fn list_dir(dir: &Path) -> Vec<String> {
.collect() .collect()
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_unpublished_operation(use_git: bool) { fn test_unpublished_operation(use_git: bool) {
// Test that the operation doesn't get published until that's requested. // Test that the operation doesn't get published until that's requested.
let settings = testutils::user_settings(); let settings = testutils::user_settings();
@ -48,8 +48,8 @@ fn test_unpublished_operation(use_git: bool) {
assert_eq!(list_dir(&op_heads_dir), vec![op_id1.hex()]); assert_eq!(list_dir(&op_heads_dir), vec![op_id1.hex()]);
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_consecutive_operations(use_git: bool) { fn test_consecutive_operations(use_git: bool) {
// Test that consecutive operations result in a single op-head on disk after // Test that consecutive operations result in a single op-head on disk after
// each operation // each operation
@ -80,8 +80,8 @@ fn test_consecutive_operations(use_git: bool) {
assert_eq!(list_dir(&op_heads_dir), vec![op_id2.hex()]); assert_eq!(list_dir(&op_heads_dir), vec![op_id2.hex()]);
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_concurrent_operations(use_git: bool) { fn test_concurrent_operations(use_git: bool) {
// Test that consecutive operations result in multiple op-heads on disk until // Test that consecutive operations result in multiple op-heads on disk until
// the repo has been reloaded (which currently happens right away). // the repo has been reloaded (which currently happens right away).
@ -125,8 +125,8 @@ fn assert_heads(repo: RepoRef, expected: Vec<&CommitId>) {
assert_eq!(*repo.view().heads(), expected); assert_eq!(*repo.view().heads(), expected);
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_isolation(use_git: bool) { fn test_isolation(use_git: bool) {
// Test that two concurrent transactions don't see each other's changes. // Test that two concurrent transactions don't see each other's changes.
let settings = testutils::user_settings(); let settings = testutils::user_settings();

View file

@ -12,17 +12,17 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use jujutsu_lib::backend::{CommitId, MillisSinceEpoch, Signature, Timestamp};
use jujutsu_lib::commit_builder::CommitBuilder; use jujutsu_lib::commit_builder::CommitBuilder;
use jujutsu_lib::op_store::RefTarget; use jujutsu_lib::op_store::RefTarget;
use jujutsu_lib::repo::RepoRef; use jujutsu_lib::repo::RepoRef;
use jujutsu_lib::revset::{parse, resolve_symbol, RevsetError}; use jujutsu_lib::revset::{parse, resolve_symbol, RevsetError};
use jujutsu_lib::store::{CommitId, MillisSinceEpoch, Signature, Timestamp};
use jujutsu_lib::testutils::CommitGraphBuilder; use jujutsu_lib::testutils::CommitGraphBuilder;
use jujutsu_lib::{git, testutils}; use jujutsu_lib::{git, testutils};
use test_case::test_case; use test_case::test_case;
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_resolve_symbol_root(use_git: bool) { fn test_resolve_symbol_root(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -232,8 +232,8 @@ fn test_resolve_symbol_change_id() {
); );
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_resolve_symbol_checkout(use_git: bool) { fn test_resolve_symbol_checkout(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -391,8 +391,8 @@ fn resolve_commit_ids(repo: RepoRef, revset_str: &str) -> Vec<CommitId> {
.collect() .collect()
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evaluate_expression_root_and_checkout(use_git: bool) { fn test_evaluate_expression_root_and_checkout(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -419,8 +419,8 @@ fn test_evaluate_expression_root_and_checkout(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evaluate_expression_parents(use_git: bool) { fn test_evaluate_expression_parents(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -481,8 +481,8 @@ fn test_evaluate_expression_parents(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evaluate_expression_children(use_git: bool) { fn test_evaluate_expression_children(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -548,8 +548,8 @@ fn test_evaluate_expression_children(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evaluate_expression_ancestors(use_git: bool) { fn test_evaluate_expression_ancestors(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -585,8 +585,8 @@ fn test_evaluate_expression_ancestors(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evaluate_expression_range(use_git: bool) { fn test_evaluate_expression_range(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -649,8 +649,8 @@ fn test_evaluate_expression_range(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evaluate_expression_dag_range(use_git: bool) { fn test_evaluate_expression_dag_range(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -724,8 +724,8 @@ fn test_evaluate_expression_dag_range(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evaluate_expression_descendants(use_git: bool) { fn test_evaluate_expression_descendants(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -782,8 +782,8 @@ fn test_evaluate_expression_descendants(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evaluate_expression_all_heads(use_git: bool) { fn test_evaluate_expression_all_heads(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -803,8 +803,8 @@ fn test_evaluate_expression_all_heads(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evaluate_expression_public_heads(use_git: bool) { fn test_evaluate_expression_public_heads(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -837,8 +837,8 @@ fn test_evaluate_expression_public_heads(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evaluate_expression_git_refs(use_git: bool) { fn test_evaluate_expression_git_refs(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -907,8 +907,8 @@ fn test_evaluate_expression_git_refs(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evaluate_expression_obsolete(use_git: bool) { fn test_evaluate_expression_obsolete(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -954,8 +954,8 @@ fn test_evaluate_expression_obsolete(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evaluate_expression_merges(use_git: bool) { fn test_evaluate_expression_merges(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -986,8 +986,8 @@ fn test_evaluate_expression_merges(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evaluate_expression_description(use_git: bool) { fn test_evaluate_expression_description(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -1033,8 +1033,8 @@ fn test_evaluate_expression_description(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evaluate_expression_union(use_git: bool) { fn test_evaluate_expression_union(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -1107,8 +1107,8 @@ fn test_evaluate_expression_union(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evaluate_expression_intersection(use_git: bool) { fn test_evaluate_expression_intersection(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -1148,8 +1148,8 @@ fn test_evaluate_expression_intersection(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_evaluate_expression_difference(use_git: bool) { fn test_evaluate_expression_difference(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);

View file

@ -19,8 +19,8 @@ use jujutsu_lib::testutils;
use jujutsu_lib::testutils::CommitGraphBuilder; use jujutsu_lib::testutils::CommitGraphBuilder;
use test_case::test_case; use test_case::test_case;
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_rebase_descendants_sideways(use_git: bool) { fn test_rebase_descendants_sideways(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -74,8 +74,8 @@ fn test_rebase_descendants_sideways(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_rebase_descendants_forward(use_git: bool) { fn test_rebase_descendants_forward(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -115,8 +115,8 @@ fn test_rebase_descendants_forward(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_rebase_descendants_backward(use_git: bool) { fn test_rebase_descendants_backward(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -153,8 +153,8 @@ fn test_rebase_descendants_backward(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_rebase_descendants_internal_merge(use_git: bool) { fn test_rebase_descendants_internal_merge(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -212,8 +212,8 @@ fn test_rebase_descendants_internal_merge(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_rebase_descendants_external_merge(use_git: bool) { fn test_rebase_descendants_external_merge(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -260,8 +260,8 @@ fn test_rebase_descendants_external_merge(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_rebase_descendants_degenerate_merge(use_git: bool) { fn test_rebase_descendants_degenerate_merge(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -300,8 +300,8 @@ fn test_rebase_descendants_degenerate_merge(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_rebase_descendants_widen_merge(use_git: bool) { fn test_rebase_descendants_widen_merge(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -351,8 +351,8 @@ fn test_rebase_descendants_widen_merge(use_git: bool) {
tx.discard(); tx.discard();
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_rebase_descendants_contents(use_git: bool) { fn test_rebase_descendants_contents(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);

View file

@ -18,8 +18,8 @@ use jujutsu_lib::testutils::CommitGraphBuilder;
use maplit::{btreemap, hashset}; use maplit::{btreemap, hashset};
use test_case::test_case; use test_case::test_case;
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_heads_empty(use_git: bool) { fn test_heads_empty(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -32,8 +32,8 @@ fn test_heads_empty(use_git: bool) {
); );
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_heads_fork(use_git: bool) { fn test_heads_fork(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
@ -56,8 +56,8 @@ fn test_heads_fork(use_git: bool) {
); );
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_heads_merge(use_git: bool) { fn test_heads_merge(use_git: bool) {
let settings = testutils::user_settings(); let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git); let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);

View file

@ -19,17 +19,17 @@ use std::os::unix::fs::PermissionsExt;
use std::sync::Arc; use std::sync::Arc;
use itertools::Itertools; use itertools::Itertools;
use jujutsu_lib::backend::TreeValue;
use jujutsu_lib::commit_builder::CommitBuilder; use jujutsu_lib::commit_builder::CommitBuilder;
use jujutsu_lib::repo::ReadonlyRepo; use jujutsu_lib::repo::ReadonlyRepo;
use jujutsu_lib::repo_path::{RepoPath, RepoPathComponent}; use jujutsu_lib::repo_path::{RepoPath, RepoPathComponent};
use jujutsu_lib::settings::UserSettings; use jujutsu_lib::settings::UserSettings;
use jujutsu_lib::store::TreeValue;
use jujutsu_lib::testutils; use jujutsu_lib::testutils;
use jujutsu_lib::tree_builder::TreeBuilder; use jujutsu_lib::tree_builder::TreeBuilder;
use test_case::test_case; use test_case::test_case;
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_root(use_git: bool) { fn test_root(use_git: bool) {
// Test that the working copy is clean and empty after init. // Test that the working copy is clean and empty after init.
let settings = testutils::user_settings(); let settings = testutils::user_settings();
@ -45,8 +45,8 @@ fn test_root(use_git: bool) {
assert_eq!(&new_tree_id, repo.store().empty_tree_id()); assert_eq!(&new_tree_id, repo.store().empty_tree_id());
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_checkout_file_transitions(use_git: bool) { fn test_checkout_file_transitions(use_git: bool) {
// Tests switching between commits where a certain path is of one type in one // Tests switching between commits where a certain path is of one type in one
// commit and another type in the other. Includes a "missing" type, so we cover // commit and another type in the other. Includes a "missing" type, so we cover
@ -234,8 +234,8 @@ fn test_checkout_file_transitions(use_git: bool) {
} }
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_commit_racy_timestamps(use_git: bool) { fn test_commit_racy_timestamps(use_git: bool) {
// Tests that file modifications are detected even if they happen the same // Tests that file modifications are detected even if they happen the same
// millisecond as the updated working copy state. // millisecond as the updated working copy state.
@ -265,8 +265,8 @@ fn test_commit_racy_timestamps(use_git: bool) {
} }
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_gitignores(use_git: bool) { fn test_gitignores(use_git: bool) {
// Tests that .gitignore files are respected. // Tests that .gitignore files are respected.
@ -335,8 +335,8 @@ fn test_gitignores(use_git: bool) {
); );
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_gitignores_checkout_overwrites_ignored(use_git: bool) { fn test_gitignores_checkout_overwrites_ignored(use_git: bool) {
// Tests that a .gitignore'd file gets overwritten if check out a commit where // Tests that a .gitignore'd file gets overwritten if check out a commit where
// the file is tracked. // the file is tracked.
@ -391,8 +391,8 @@ fn test_gitignores_checkout_overwrites_ignored(use_git: bool) {
.is_some()); .is_some());
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_gitignores_ignored_directory_already_tracked(use_git: bool) { fn test_gitignores_ignored_directory_already_tracked(use_git: bool) {
// Tests that a .gitignore'd directory that already has a tracked file in it // Tests that a .gitignore'd directory that already has a tracked file in it
// does not get removed when committing the working directory. // does not get removed when committing the working directory.
@ -435,8 +435,8 @@ fn test_gitignores_ignored_directory_already_tracked(use_git: bool) {
assert!(new_tree.path_value(&file_path).is_some()); assert!(new_tree.path_value(&file_path).is_some());
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_dotgit_ignored(use_git: bool) { fn test_dotgit_ignored(use_git: bool) {
// Tests that .git directories and files are always ignored (we could accept // Tests that .git directories and files are always ignored (we could accept
// them if the backend is not git). // them if the backend is not git).

View file

@ -23,8 +23,8 @@ use jujutsu_lib::testutils;
use jujutsu_lib::working_copy::CheckoutError; use jujutsu_lib::working_copy::CheckoutError;
use test_case::test_case; use test_case::test_case;
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_concurrent_checkout(use_git: bool) { fn test_concurrent_checkout(use_git: bool) {
// Test that we error out if a concurrent checkout is detected (i.e. if the // Test that we error out if a concurrent checkout is detected (i.e. if the
// current checkout changed on disk after we read it). // current checkout changed on disk after we read it).
@ -68,8 +68,8 @@ fn test_concurrent_checkout(use_git: bool) {
); );
} }
#[test_case(false ; "local store")] #[test_case(false ; "local backend")]
#[test_case(true ; "git store")] #[test_case(true ; "git backend")]
fn test_checkout_parallel(use_git: bool) { fn test_checkout_parallel(use_git: bool) {
// Test that concurrent checkouts by different processes (simulated by using // Test that concurrent checkouts by different processes (simulated by using
// different repo instances) is safe. // different repo instances) is safe.

View file

@ -31,6 +31,7 @@ use std::{fs, io};
use clap::{crate_version, App, Arg, ArgMatches, SubCommand}; use clap::{crate_version, App, Arg, ArgMatches, SubCommand};
use criterion::Criterion; use criterion::Criterion;
use itertools::Itertools; use itertools::Itertools;
use jujutsu_lib::backend::{BackendError, CommitId, Timestamp, TreeValue};
use jujutsu_lib::commit::Commit; use jujutsu_lib::commit::Commit;
use jujutsu_lib::commit_builder::CommitBuilder; use jujutsu_lib::commit_builder::CommitBuilder;
use jujutsu_lib::dag_walk::topo_order_reverse; use jujutsu_lib::dag_walk::topo_order_reverse;
@ -53,8 +54,7 @@ use jujutsu_lib::revset::{RevsetError, RevsetExpression, RevsetParseError};
use jujutsu_lib::revset_graph_iterator::RevsetGraphEdgeType; use jujutsu_lib::revset_graph_iterator::RevsetGraphEdgeType;
use jujutsu_lib::rewrite::{back_out_commit, merge_commit_trees, rebase_commit, DescendantRebaser}; use jujutsu_lib::rewrite::{back_out_commit, merge_commit_trees, rebase_commit, DescendantRebaser};
use jujutsu_lib::settings::UserSettings; use jujutsu_lib::settings::UserSettings;
use jujutsu_lib::store::{CommitId, StoreError, Timestamp, TreeValue}; use jujutsu_lib::store::Store;
use jujutsu_lib::store_wrapper::StoreWrapper;
use jujutsu_lib::transaction::Transaction; use jujutsu_lib::transaction::Transaction;
use jujutsu_lib::tree::{Diff, DiffSummary}; use jujutsu_lib::tree::{Diff, DiffSummary};
use jujutsu_lib::working_copy::{CheckoutStats, WorkingCopy}; use jujutsu_lib::working_copy::{CheckoutStats, WorkingCopy};
@ -87,8 +87,8 @@ impl From<std::io::Error> for CommandError {
} }
} }
impl From<StoreError> for CommandError { impl From<BackendError> for CommandError {
fn from(err: StoreError) -> Self { fn from(err: BackendError) -> Self {
CommandError::UserError(format!("Unexpected error from store: {}", err)) CommandError::UserError(format!("Unexpected error from store: {}", err))
} }
} }
@ -3205,7 +3205,7 @@ fn cmd_operation(
Ok(()) Ok(())
} }
fn get_git_repo(store: &StoreWrapper) -> Result<git2::Repository, CommandError> { fn get_git_repo(store: &Store) -> Result<git2::Repository, CommandError> {
match store.git_repo() { match store.git_repo() {
None => Err(CommandError::UserError( None => Err(CommandError::UserError(
"The repo is not backed by a git repo".to_string(), "The repo is not backed by a git repo".to_string(),

View file

@ -18,10 +18,10 @@ use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
use std::sync::Arc; use std::sync::Arc;
use jujutsu_lib::backend::{BackendError, TreeId, TreeValue};
use jujutsu_lib::matchers::EverythingMatcher; use jujutsu_lib::matchers::EverythingMatcher;
use jujutsu_lib::repo_path::RepoPath; use jujutsu_lib::repo_path::RepoPath;
use jujutsu_lib::store::{StoreError, TreeId, TreeValue}; use jujutsu_lib::store::Store;
use jujutsu_lib::store_wrapper::StoreWrapper;
use jujutsu_lib::tree::{merge_trees, Tree}; use jujutsu_lib::tree::{merge_trees, Tree};
use jujutsu_lib::tree_builder::TreeBuilder; use jujutsu_lib::tree_builder::TreeBuilder;
use jujutsu_lib::working_copy::{CheckoutError, TreeState}; use jujutsu_lib::working_copy::{CheckoutError, TreeState};
@ -37,7 +37,7 @@ pub enum DiffEditError {
#[error("Failed to write directories to diff: {0:?}")] #[error("Failed to write directories to diff: {0:?}")]
CheckoutError(CheckoutError), CheckoutError(CheckoutError),
#[error("Internal error: {0:?}")] #[error("Internal error: {0:?}")]
InternalStoreError(StoreError), InternalBackendError(BackendError),
} }
impl From<CheckoutError> for DiffEditError { impl From<CheckoutError> for DiffEditError {
@ -46,18 +46,18 @@ impl From<CheckoutError> for DiffEditError {
} }
} }
impl From<StoreError> for DiffEditError { impl From<BackendError> for DiffEditError {
fn from(err: StoreError) -> Self { fn from(err: BackendError) -> Self {
DiffEditError::InternalStoreError(err) DiffEditError::InternalBackendError(err)
} }
} }
fn add_to_tree( fn add_to_tree(
store: &StoreWrapper, store: &Store,
tree_builder: &mut TreeBuilder, tree_builder: &mut TreeBuilder,
repo_path: &RepoPath, repo_path: &RepoPath,
value: &TreeValue, value: &TreeValue,
) -> Result<(), StoreError> { ) -> Result<(), BackendError> {
match value { match value {
TreeValue::Conflict(conflict_id) => { TreeValue::Conflict(conflict_id) => {
let conflict = store.read_conflict(conflict_id)?; let conflict = store.read_conflict(conflict_id)?;
@ -73,7 +73,7 @@ fn add_to_tree(
} }
fn check_out( fn check_out(
store: Arc<StoreWrapper>, store: Arc<Store>,
wc_dir: PathBuf, wc_dir: PathBuf,
state_dir: PathBuf, state_dir: PathBuf,
tree_id: TreeId, tree_id: TreeId,

View file

@ -15,9 +15,9 @@
extern crate pest; extern crate pest;
use chrono::{FixedOffset, TimeZone, Utc}; use chrono::{FixedOffset, TimeZone, Utc};
use jujutsu_lib::backend::{CommitId, Signature};
use jujutsu_lib::commit::Commit; use jujutsu_lib::commit::Commit;
use jujutsu_lib::repo::RepoRef; use jujutsu_lib::repo::RepoRef;
use jujutsu_lib::store::{CommitId, Signature};
use pest::iterators::{Pair, Pairs}; use pest::iterators::{Pair, Pairs};
use pest::Parser; use pest::Parser;

View file

@ -17,9 +17,9 @@ use std::io;
use std::ops::Add; use std::ops::Add;
use itertools::Itertools; use itertools::Itertools;
use jujutsu_lib::backend::{CommitId, Signature};
use jujutsu_lib::commit::Commit; use jujutsu_lib::commit::Commit;
use jujutsu_lib::repo::RepoRef; use jujutsu_lib::repo::RepoRef;
use jujutsu_lib::store::{CommitId, Signature};
use crate::formatter::Formatter; use crate::formatter::Formatter;