lib: rename the LocalBackend to SimpleBackend

This makes it clear to source code readers, that it isn't the _native backend_ the project
talks about in the Roadmap.
This commit is contained in:
Philip Metzger 2025-02-27 17:55:39 +01:00 committed by Philip Metzger
parent 76bff8fa34
commit f8ab8a0e72
21 changed files with 163 additions and 53 deletions

View File

@ -24,27 +24,24 @@ use crate::command_error::user_error_with_message;
use crate::command_error::CommandError;
use crate::ui::Ui;
/// Create a new repo in the given directory using the proof-of-concept native
/// Create a new repo in the given directory using the proof-of-concept simple
/// backend
///
/// The proof-of-concept backend is called "local" because it does not support
/// cloning, pushing, or fetching repositories or commits.
///
/// This command is otherwise analogous to `jj git init`. If the given directory
/// does not exist, it will be created. If no directory is given, the current
/// directory is used.
#[derive(clap::Args, Clone, Debug)]
pub(crate) struct DebugInitLocalArgs {
pub(crate) struct DebugInitSimpleArgs {
/// The destination directory
#[arg(default_value = ".", value_hint = clap::ValueHint::DirPath)]
destination: String,
}
#[instrument(skip_all)]
pub(crate) fn cmd_debug_init_local(
pub(crate) fn cmd_debug_init_simple(
ui: &mut Ui,
command: &CommandHelper,
args: &DebugInitLocalArgs,
args: &DebugInitSimpleArgs,
) -> Result<(), CommandError> {
if command.global_args().ignore_working_copy {
return Err(cli_error("--ignore-working-copy is not respected"));
@ -58,7 +55,7 @@ pub(crate) fn cmd_debug_init_local(
.and_then(|_| dunce::canonicalize(wc_path))
.map_err(|e| user_error_with_message("Failed to create workspace", e))?;
Workspace::init_local(&command.settings_for_new_workspace(&wc_path)?, &wc_path)?;
Workspace::init_simple(&command.settings_for_new_workspace(&wc_path)?, &wc_path)?;
let relative_wc_path = file_util::relative_path(cwd, &wc_path);
writeln!(

View File

@ -15,7 +15,7 @@
mod copy_detection;
mod fileset;
mod index;
mod init_local;
mod init_simple;
mod local_working_copy;
mod operation;
mod reindex;
@ -38,8 +38,8 @@ use self::fileset::cmd_debug_fileset;
use self::fileset::DebugFilesetArgs;
use self::index::cmd_debug_index;
use self::index::DebugIndexArgs;
use self::init_local::cmd_debug_init_local;
use self::init_local::DebugInitLocalArgs;
use self::init_simple::cmd_debug_init_simple;
use self::init_simple::DebugInitSimpleArgs;
use self::local_working_copy::cmd_debug_local_working_copy;
use self::local_working_copy::DebugLocalWorkingCopyArgs;
use self::operation::cmd_debug_operation;
@ -70,7 +70,7 @@ pub enum DebugCommand {
CopyDetection(CopyDetectionArgs),
Fileset(DebugFilesetArgs),
Index(DebugIndexArgs),
InitLocal(DebugInitLocalArgs),
InitSimple(DebugInitSimpleArgs),
LocalWorkingCopy(DebugLocalWorkingCopyArgs),
#[command(visible_alias = "view")]
Operation(DebugOperationArgs),
@ -93,7 +93,7 @@ pub fn cmd_debug(
DebugCommand::CopyDetection(args) => cmd_debug_copy_detection(ui, command, args),
DebugCommand::Fileset(args) => cmd_debug_fileset(ui, command, args),
DebugCommand::Index(args) => cmd_debug_index(ui, command, args),
DebugCommand::InitLocal(args) => cmd_debug_init_local(ui, command, args),
DebugCommand::InitSimple(args) => cmd_debug_init_simple(ui, command, args),
DebugCommand::LocalWorkingCopy(args) => cmd_debug_local_working_copy(ui, command, args),
DebugCommand::Operation(args) => cmd_debug_operation(ui, command, args),
DebugCommand::Reindex(args) => cmd_debug_reindex(ui, command, args),

View File

@ -24,7 +24,7 @@ mod test_config_command;
mod test_config_schema;
mod test_copy_detection;
mod test_debug_command;
mod test_debug_init_local_command;
mod test_debug_init_simple_command;
mod test_describe_command;
mod test_diff_command;
mod test_diffedit_command;

View File

@ -17,7 +17,7 @@ use crate::common::TestEnvironment;
#[test]
fn test_init_local() {
let test_env = TestEnvironment::default();
let output = test_env.run_jj_in(".", ["debug", "init-local", "repo"]);
let output = test_env.run_jj_in(".", ["debug", "init-simple", "repo"]);
insta::assert_snapshot!(output, @r#"
------- stderr -------
Initialized repo in "repo"
@ -41,7 +41,7 @@ fn test_init_local() {
let output = test_env.run_jj_in(
".",
["debug", "init-local", "--ignore-working-copy", "repo2"],
["debug", "init-simple", "--ignore-working-copy", "repo2"],
);
insta::assert_snapshot!(output, @r"
------- stderr -------
@ -50,7 +50,7 @@ fn test_init_local() {
[exit status: 2]
");
let output = test_env.run_jj_in(".", ["debug", "init-local", "--at-op=@-", "repo3"]);
let output = test_env.run_jj_in(".", ["debug", "init-simple", "--at-op=@-", "repo3"]);
insta::assert_snapshot!(output, @r"
------- stderr -------
Error: --at-op is not respected

View File

@ -20,7 +20,7 @@ use testutils::TestWorkspace;
use crate::common::TestEnvironment;
#[test_case(TestRepoBackend::Local ; "local backend")]
#[test_case(TestRepoBackend::Simple ; "simple backend")]
#[test_case(TestRepoBackend::Git ; "git backend")]
fn test_root(backend: TestRepoBackend) {
let test_env = TestEnvironment::default();

View File

@ -88,9 +88,9 @@ Because we use the Git Object ID as commit ID, two commits that differ only in
their change ID, for example, will get the same commit ID, so we error out when
trying to write the second one of them.
### LocalBackend
### SimpleBackend
The `LocalBackend` is just a proof of concept. It stores objects addressed by
The `SimpleBackend` is just a proof of concept. It stores objects addressed by
their hash, with one file per object.
### Store

View File

@ -18,7 +18,7 @@ use std::path::Path;
fn main() -> Result<()> {
let input = [
"git_store.proto",
"local_store.proto",
"simple_store.proto",
"op_store.proto",
"working_copy.proto",
];

View File

@ -74,7 +74,6 @@ pub mod graph;
pub mod hex_util;
pub mod id_prefix;
pub mod index;
pub mod local_backend;
pub mod local_working_copy;
pub mod lock;
pub mod matchers;
@ -97,6 +96,10 @@ pub mod rewrite;
pub mod secret_backend;
pub mod settings;
pub mod signing;
// TODO: This file is mostly used for testing, whenever we no longer require it
// in the lib it should be moved to the examples (e.g
// "examples/simple-backend/").
pub mod simple_backend;
pub mod simple_op_heads_store;
pub mod simple_op_store;
pub mod ssh_signing;

View File

@ -0,0 +1,109 @@
// This file is @generated by prost-build.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TreeValue {
#[prost(oneof = "tree_value::Value", tags = "2, 3, 4, 5")]
pub value: ::core::option::Option<tree_value::Value>,
}
/// Nested message and enum types in `TreeValue`.
pub mod tree_value {
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct File {
#[prost(bytes = "vec", tag = "1")]
pub id: ::prost::alloc::vec::Vec<u8>,
#[prost(bool, tag = "2")]
pub executable: bool,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Oneof)]
pub enum Value {
#[prost(message, tag = "2")]
File(File),
#[prost(bytes, tag = "3")]
SymlinkId(::prost::alloc::vec::Vec<u8>),
#[prost(bytes, tag = "4")]
TreeId(::prost::alloc::vec::Vec<u8>),
#[prost(bytes, tag = "5")]
ConflictId(::prost::alloc::vec::Vec<u8>),
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Tree {
#[prost(message, repeated, tag = "1")]
pub entries: ::prost::alloc::vec::Vec<tree::Entry>,
}
/// Nested message and enum types in `Tree`.
pub mod tree {
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Entry {
#[prost(string, tag = "1")]
pub name: ::prost::alloc::string::String,
#[prost(message, optional, tag = "2")]
pub value: ::core::option::Option<super::TreeValue>,
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Commit {
#[prost(bytes = "vec", repeated, tag = "1")]
pub parents: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
#[prost(bytes = "vec", repeated, tag = "2")]
pub predecessors: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
/// Alternating positive and negative terms
#[prost(bytes = "vec", repeated, tag = "3")]
pub root_tree: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
/// TODO(#1624): delete when all code paths can handle this format
#[prost(bool, tag = "8")]
pub uses_tree_conflict_format: bool,
#[prost(bytes = "vec", tag = "4")]
pub change_id: ::prost::alloc::vec::Vec<u8>,
#[prost(string, tag = "5")]
pub description: ::prost::alloc::string::String,
#[prost(message, optional, tag = "6")]
pub author: ::core::option::Option<commit::Signature>,
#[prost(message, optional, tag = "7")]
pub committer: ::core::option::Option<commit::Signature>,
#[prost(bytes = "vec", optional, tag = "9")]
pub secure_sig: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,
}
/// Nested message and enum types in `Commit`.
pub mod commit {
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Timestamp {
#[prost(int64, tag = "1")]
pub millis_since_epoch: i64,
#[prost(int32, tag = "2")]
pub tz_offset: i32,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Signature {
#[prost(string, tag = "1")]
pub name: ::prost::alloc::string::String,
#[prost(string, tag = "2")]
pub email: ::prost::alloc::string::String,
#[prost(message, optional, tag = "3")]
pub timestamp: ::core::option::Option<Timestamp>,
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Conflict {
#[prost(message, repeated, tag = "1")]
pub removes: ::prost::alloc::vec::Vec<conflict::Term>,
#[prost(message, repeated, tag = "2")]
pub adds: ::prost::alloc::vec::Vec<conflict::Term>,
}
/// Nested message and enum types in `Conflict`.
pub mod conflict {
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Term {
#[prost(message, optional, tag = "1")]
pub content: ::core::option::Option<super::TreeValue>,
}
}

View File

@ -54,7 +54,6 @@ use crate::index::IndexReadError;
use crate::index::IndexStore;
use crate::index::MutableIndex;
use crate::index::ReadonlyIndex;
use crate::local_backend::LocalBackend;
use crate::merge::MergeBuilder;
use crate::object_id::HexPrefix;
use crate::object_id::ObjectId as _;
@ -91,6 +90,7 @@ use crate::rewrite::RewriteRefsOptions;
use crate::settings::UserSettings;
use crate::signing::SignInitError;
use crate::signing::Signer;
use crate::simple_backend::SimpleBackend;
use crate::simple_op_heads_store::SimpleOpHeadsStore;
use crate::simple_op_store::SimpleOpStore;
use crate::store::Store;
@ -396,9 +396,10 @@ impl Default for StoreFactories {
let mut factories = StoreFactories::empty();
// Backends
#[cfg(feature = "testing")]
factories.add_backend(
LocalBackend::name(),
Box::new(|_settings, store_path| Ok(Box::new(LocalBackend::load(store_path)))),
SimpleBackend::name(),
Box::new(|_settings, store_path| Ok(Box::new(SimpleBackend::load(store_path)))),
);
#[cfg(feature = "git")]
factories.add_backend(

View File

@ -88,16 +88,16 @@ fn to_other_err(err: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> Bac
}
#[derive(Debug)]
pub struct LocalBackend {
pub struct SimpleBackend {
path: PathBuf,
root_commit_id: CommitId,
root_change_id: ChangeId,
empty_tree_id: TreeId,
}
impl LocalBackend {
impl SimpleBackend {
pub fn name() -> &'static str {
"local"
"Simple"
}
pub fn init(store_path: &Path) -> Self {
@ -121,7 +121,7 @@ impl LocalBackend {
let empty_tree_id = TreeId::from_hex(
"482ae5a29fbe856c7272f2071b8b0f0359ee2d89ff392b8a900643fbd0836eccd067b8bf41909e206c90d45d6e7d8b6686b93ecaee5fe1a9060d87b672101310",
);
LocalBackend {
SimpleBackend {
path: store_path.to_path_buf(),
root_commit_id,
root_change_id,
@ -151,7 +151,7 @@ impl LocalBackend {
}
#[async_trait]
impl Backend for LocalBackend {
impl Backend for SimpleBackend {
fn as_any(&self) -> &dyn Any {
self
}
@ -352,7 +352,7 @@ impl Backend for LocalBackend {
}
}
#[expect(clippy::assigning_clones)]
#[allow(clippy::assigning_clones)]
pub fn commit_to_proto(commit: &Commit) -> crate::protos::local_store::Commit {
let mut proto = crate::protos::local_store::Commit::default();
for parent in &commit.parents {
@ -554,7 +554,7 @@ mod tests {
let temp_dir = new_temp_dir();
let store_path = temp_dir.path();
let backend = LocalBackend::init(store_path);
let backend = SimpleBackend::init(store_path);
let mut commit = Commit {
parents: vec![],
predecessors: vec![],

View File

@ -30,7 +30,6 @@ use crate::backend::MergedTreeId;
use crate::commit::Commit;
use crate::file_util::IoResultExt as _;
use crate::file_util::PathError;
use crate::local_backend::LocalBackend;
use crate::local_working_copy::LocalWorkingCopy;
use crate::local_working_copy::LocalWorkingCopyFactory;
use crate::op_heads_store::OpHeadsStoreError;
@ -52,6 +51,7 @@ use crate::repo::SubmoduleStoreInitializer;
use crate::settings::UserSettings;
use crate::signing::SignInitError;
use crate::signing::Signer;
use crate::simple_backend::SimpleBackend;
use crate::store::Store;
use crate::working_copy::CheckoutError;
use crate::working_copy::CheckoutOptions;
@ -180,12 +180,12 @@ impl Workspace {
}
}
pub fn init_local(
pub fn init_simple(
user_settings: &UserSettings,
workspace_root: &Path,
) -> Result<(Self, Arc<ReadonlyRepo>), WorkspaceInitError> {
let backend_initializer: &BackendInitializer =
&|_settings, store_path| Ok(Box::new(LocalBackend::init(store_path)));
&|_settings, store_path| Ok(Box::new(SimpleBackend::init(store_path)));
let signer = Signer::from_settings(user_settings)?;
Self::init_with_backend(user_settings, workspace_root, backend_initializer, signer)
}

View File

@ -99,7 +99,7 @@ fn merge_directories(left: &Path, base: &Path, right: &Path, output: &Path) {
}
}
#[test_case(TestRepoBackend::Local; "local backend")]
#[test_case(TestRepoBackend::Simple; "simple backend")]
#[test_case(TestRepoBackend::Git; "git backend")]
fn test_bad_locking_children(backend: TestRepoBackend) {
// Test that two new commits created on separate machines are both visible (not
@ -171,7 +171,7 @@ fn test_bad_locking_children(backend: TestRepoBackend) {
assert_eq!(op.parents.len(), 2);
}
#[test_case(TestRepoBackend::Local ; "local backend")]
#[test_case(TestRepoBackend::Simple ; "simple backend")]
#[test_case(TestRepoBackend::Git ; "git backend")]
fn test_bad_locking_interrupted(backend: TestRepoBackend) {
// Test that an interrupted update of the op-heads resulting in on op-head

View File

@ -63,7 +63,7 @@ fn to_owned_path_vec(paths: &[&RepoPath]) -> Vec<RepoPathBuf> {
paths.iter().map(|&path| path.to_owned()).collect()
}
#[test_case(TestRepoBackend::Local ; "local backend")]
#[test_case(TestRepoBackend::Simple ; "simple backend")]
#[test_case(TestRepoBackend::Git ; "git backend")]
fn test_initial(backend: TestRepoBackend) {
let test_repo = TestRepo::init_with_backend(backend);
@ -129,7 +129,7 @@ fn test_initial(backend: TestRepoBackend) {
);
}
#[test_case(TestRepoBackend::Local ; "local backend")]
#[test_case(TestRepoBackend::Simple ; "simple backend")]
#[test_case(TestRepoBackend::Git ; "git backend")]
fn test_rewrite(backend: TestRepoBackend) {
let settings = testutils::user_settings();
@ -219,7 +219,7 @@ fn test_rewrite(backend: TestRepoBackend) {
}
// An author field with an empty name/email should get filled in on rewrite
#[test_case(TestRepoBackend::Local ; "local backend")]
#[test_case(TestRepoBackend::Simple ; "simple backend")]
#[test_case(TestRepoBackend::Git ; "git backend")]
fn test_rewrite_update_missing_user(backend: TestRepoBackend) {
let missing_user_settings = UserSettings::from_config(StackedConfig::with_defaults()).unwrap();
@ -275,7 +275,7 @@ fn test_rewrite_update_missing_user(backend: TestRepoBackend) {
);
}
#[test_case(TestRepoBackend::Local ; "local backend")]
#[test_case(TestRepoBackend::Simple ; "simple backend")]
#[test_case(TestRepoBackend::Git ; "git backend")]
fn test_rewrite_resets_author_timestamp(backend: TestRepoBackend) {
let test_repo = TestRepo::init_with_backend(backend);
@ -350,7 +350,7 @@ fn test_rewrite_resets_author_timestamp(backend: TestRepoBackend) {
assert_eq!(rewritten_commit_2.committer().timestamp, new_timestamp_2);
}
#[test_case(TestRepoBackend::Local ; "local backend")]
#[test_case(TestRepoBackend::Simple ; "simple backend")]
// #[test_case(TestRepoBackend::Git ; "git backend")]
fn test_commit_builder_descendants(backend: TestRepoBackend) {
let test_repo = TestRepo::init_with_backend(backend);

View File

@ -41,7 +41,7 @@ fn count_non_merge_operations(repo: &Arc<ReadonlyRepo>) -> usize {
num_ops
}
#[test_case(TestRepoBackend::Local ; "local backend")]
#[test_case(TestRepoBackend::Simple ; "simple backend")]
#[test_case(TestRepoBackend::Git ; "git backend")]
fn test_commit_parallel(backend: TestRepoBackend) {
// This loads a Repo instance and creates and commits many concurrent
@ -71,7 +71,7 @@ fn test_commit_parallel(backend: TestRepoBackend) {
assert_eq!(count_non_merge_operations(&repo), num_threads + 2);
}
#[test_case(TestRepoBackend::Local ; "local backend")]
#[test_case(TestRepoBackend::Simple ; "simple backend")]
#[test_case(TestRepoBackend::Git ; "git backend")]
fn test_commit_parallel_instances(backend: TestRepoBackend) {
// Like the test above but creates a new repo instance for every thread, which

View File

@ -38,7 +38,7 @@ fn test_init_local() {
let settings = testutils::user_settings();
let temp_dir = testutils::new_temp_dir();
let (canonical, uncanonical) = canonicalize(temp_dir.path());
let (workspace, repo) = Workspace::init_local(&settings, &uncanonical).unwrap();
let (workspace, repo) = Workspace::init_simple(&settings, &uncanonical).unwrap();
assert!(repo
.store()
.backend_impl()
@ -138,7 +138,7 @@ fn test_init_external_git() {
write_random_commit(tx.repo_mut());
}
#[test_case(TestRepoBackend::Local ; "local backend")]
#[test_case(TestRepoBackend::Simple ; "simple backend")]
#[test_case(TestRepoBackend::Git ; "git backend")]
fn test_init_with_default_config(backend: TestRepoBackend) {
// Test that we can create a repo without setting any non-default config
@ -156,7 +156,7 @@ fn test_init_with_default_config(backend: TestRepoBackend) {
assert_eq!(wc_commit.committer().email, "".to_string());
}
#[test_case(TestRepoBackend::Local ; "local backend")]
#[test_case(TestRepoBackend::Simple ; "simple backend")]
#[test_case(TestRepoBackend::Git ; "git backend")]
fn test_init_checkout(backend: TestRepoBackend) {
// Test the contents of the working-copy commit after init

View File

@ -122,7 +122,7 @@ fn test_root() {
assert_eq!(new_tree.id(), repo.store().empty_merged_tree_id());
}
#[test_case(TestRepoBackend::Local ; "local backend")]
#[test_case(TestRepoBackend::Simple ; "simple backend")]
#[test_case(TestRepoBackend::Git ; "git backend")]
fn test_checkout_file_transitions(backend: TestRepoBackend) {
// Tests switching between commits where a certain path is of one type in one

View File

@ -58,7 +58,7 @@ fn good_verification() -> Option<Verification> {
})
}
#[test_case(TestRepoBackend::Local ; "local backend")]
#[test_case(TestRepoBackend::Simple ; "simple backend")]
#[test_case(TestRepoBackend::Git ; "git backend")]
fn manual(backend: TestRepoBackend) {
let settings = user_settings(SignBehavior::Own);

View File

@ -40,7 +40,6 @@ use jj_lib::config::ConfigLayer;
use jj_lib::config::ConfigSource;
use jj_lib::config::StackedConfig;
use jj_lib::git_backend::GitBackend;
use jj_lib::local_backend::LocalBackend;
use jj_lib::merged_tree::MergedTree;
use jj_lib::object_id::ObjectId as _;
use jj_lib::repo::MutableRepo;
@ -55,6 +54,7 @@ use jj_lib::rewrite::RebasedCommit;
use jj_lib::secret_backend::SecretBackend;
use jj_lib::settings::UserSettings;
use jj_lib::signing::Signer;
use jj_lib::simple_backend::SimpleBackend;
use jj_lib::store::Store;
use jj_lib::transaction::Transaction;
use jj_lib::tree::Tree;
@ -189,7 +189,7 @@ pub struct TestRepo {
#[derive(PartialEq, Eq, Copy, Clone)]
pub enum TestRepoBackend {
Git,
Local,
Simple,
Test,
}
@ -202,7 +202,7 @@ impl TestRepoBackend {
) -> Result<Box<dyn Backend>, BackendInitError> {
match self {
TestRepoBackend::Git => Ok(Box::new(GitBackend::init_internal(settings, store_path)?)),
TestRepoBackend::Local => Ok(Box::new(LocalBackend::init(store_path))),
TestRepoBackend::Simple => Ok(Box::new(SimpleBackend::init(store_path))),
TestRepoBackend::Test => Ok(Box::new(env.test_backend_factory.init(store_path))),
}
}

View File

@ -109,7 +109,7 @@ fn get_hash(content: &(impl jj_lib::content_hash::ContentHash + ?Sized)) -> Vec<
///
/// It's meant to be strict, in order to catch bugs where we make the
/// wrong assumptions. For example, unlike both `GitBackend` and
/// `LocalBackend`, this backend doesn't share objects written to
/// `SimpleBackend`, this backend doesn't share objects written to
/// different paths (writing a file with contents X to path A will not
/// make it possible to read that contents from path B given the same
/// `FileId`).