diff --git a/lib/src/repo.rs b/lib/src/repo.rs index b5c3ea0ff..36eca5e81 100644 --- a/lib/src/repo.rs +++ b/lib/src/repo.rs @@ -131,6 +131,12 @@ impl Debug for ReadonlyRepo { } } +#[derive(Error, Debug, PartialEq)] +pub enum RepoInitError { + #[error("The destination repo ({0}) already exists")] + DestinationExists(PathBuf), +} + #[derive(Error, Debug, PartialEq)] pub enum RepoLoadError { #[error("There is no Jujutsu repo in {0}")] @@ -138,19 +144,23 @@ pub enum RepoLoadError { } impl ReadonlyRepo { - pub fn init_local(settings: &UserSettings, wc_path: PathBuf) -> Arc { - let repo_path = wc_path.join(".jj"); - fs::create_dir(repo_path.clone()).unwrap(); + pub fn init_local( + settings: &UserSettings, + wc_path: PathBuf, + ) -> Result, RepoInitError> { + let repo_path = ReadonlyRepo::init_repo_dir(&wc_path)?; let store_path = repo_path.join("store"); fs::create_dir(&store_path).unwrap(); let store = Box::new(LocalStore::init(store_path)); - ReadonlyRepo::init(settings, repo_path, wc_path, store) + Ok(ReadonlyRepo::init(settings, repo_path, wc_path, store)) } /// Initializes a repo with a new Git store in .jj/git/ (bare Git repo) - pub fn init_internal_git(settings: &UserSettings, wc_path: PathBuf) -> Arc { - let repo_path = wc_path.join(".jj"); - fs::create_dir(repo_path.clone()).unwrap(); + pub fn init_internal_git( + settings: &UserSettings, + wc_path: PathBuf, + ) -> Result, RepoInitError> { + let repo_path = ReadonlyRepo::init_repo_dir(&wc_path)?; let git_store_path = repo_path.join("git"); git2::Repository::init_bare(&git_store_path).unwrap(); let store_path = repo_path.join("store"); @@ -158,7 +168,7 @@ impl ReadonlyRepo { let mut store_file = File::create(store_path).unwrap(); store_file.write_all(b"git: git").unwrap(); let store = Box::new(GitStore::load(&git_store_path)); - ReadonlyRepo::init(settings, repo_path, wc_path, store) + Ok(ReadonlyRepo::init(settings, repo_path, wc_path, store)) } /// Initializes a repo with an existing Git store at the specified path @@ -166,9 +176,8 @@ impl ReadonlyRepo { settings: &UserSettings, wc_path: PathBuf, git_store_path: PathBuf, - ) -> Arc { - let repo_path = wc_path.join(".jj"); - fs::create_dir(repo_path.clone()).unwrap(); + ) -> Result, RepoInitError> { + let repo_path = ReadonlyRepo::init_repo_dir(&wc_path)?; let store_path = repo_path.join("store"); let git_store_path = fs::canonicalize(git_store_path).unwrap(); let mut store_file = File::create(store_path).unwrap(); @@ -176,7 +185,17 @@ impl ReadonlyRepo { .write_all(format!("git: {}", git_store_path.to_str().unwrap()).as_bytes()) .unwrap(); let store = Box::new(GitStore::load(&git_store_path)); - ReadonlyRepo::init(settings, repo_path, wc_path, store) + Ok(ReadonlyRepo::init(settings, repo_path, wc_path, store)) + } + + fn init_repo_dir(wc_path: &Path) -> Result { + let repo_path = wc_path.join(".jj"); + if repo_path.exists() { + Err(RepoInitError::DestinationExists(repo_path)) + } else { + fs::create_dir(&repo_path).unwrap(); + Ok(repo_path) + } } fn init( diff --git a/lib/src/testutils.rs b/lib/src/testutils.rs index 09ab9f380..dbc3d1d43 100644 --- a/lib/src/testutils.rs +++ b/lib/src/testutils.rs @@ -53,9 +53,9 @@ pub fn init_repo(settings: &UserSettings, use_git: bool) -> (TempDir, Arc PushTestSet let initial_commit_id = commit_id(&initial_git_commit); git2::Repository::clone(&source_repo_dir.to_str().unwrap(), &clone_repo_dir).unwrap(); std::fs::create_dir(&jj_repo_dir).unwrap(); - let jj_repo = ReadonlyRepo::init_external_git(&settings, jj_repo_dir, clone_repo_dir); + let jj_repo = ReadonlyRepo::init_external_git(&settings, jj_repo_dir, clone_repo_dir).unwrap(); let new_commit = testutils::create_random_commit(&settings, &jj_repo) .set_parents(vec![initial_commit_id]) .write_to_new_transaction(&jj_repo, "test"); diff --git a/lib/tests/test_init.rs b/lib/tests/test_init.rs index 400060278..599408e7f 100644 --- a/lib/tests/test_init.rs +++ b/lib/tests/test_init.rs @@ -22,7 +22,7 @@ fn test_init_local() { let settings = testutils::user_settings(); let temp_dir = tempfile::tempdir().unwrap(); let wc_path = temp_dir.path().to_owned(); - let repo = ReadonlyRepo::init_local(&settings, wc_path.clone()); + let repo = ReadonlyRepo::init_local(&settings, wc_path.clone()).unwrap(); assert!(repo.store().git_repo().is_none()); assert_eq!(repo.working_copy_path(), &wc_path); assert_eq!(repo.repo_path(), &wc_path.join(".jj")); @@ -38,7 +38,7 @@ fn test_init_internal_git() { let settings = testutils::user_settings(); let temp_dir = tempfile::tempdir().unwrap(); let wc_path = temp_dir.path().to_owned(); - let repo = ReadonlyRepo::init_internal_git(&settings, wc_path.clone()); + let repo = ReadonlyRepo::init_internal_git(&settings, wc_path.clone()).unwrap(); assert!(repo.store().git_repo().is_some()); assert_eq!(repo.working_copy_path(), &wc_path); assert_eq!(repo.repo_path(), &wc_path.join(".jj")); @@ -57,7 +57,7 @@ fn test_init_external_git() { git2::Repository::init(&git_repo_path).unwrap(); let wc_path = temp_dir.path().join("jj"); std::fs::create_dir(&wc_path).unwrap(); - let repo = ReadonlyRepo::init_external_git(&settings, wc_path.clone(), git_repo_path); + let repo = ReadonlyRepo::init_external_git(&settings, wc_path.clone(), git_repo_path).unwrap(); assert!(repo.store().git_repo().is_some()); assert_eq!(repo.working_copy_path(), &wc_path); assert_eq!(repo.repo_path(), &wc_path.join(".jj")); diff --git a/src/commands.rs b/src/commands.rs index 59753c4c7..241c3f877 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -40,7 +40,7 @@ use jujutsu_lib::git::GitFetchError; use jujutsu_lib::index::HexPrefix; use jujutsu_lib::op_store::{OpStore, OpStoreError, OperationId}; use jujutsu_lib::operation::Operation; -use jujutsu_lib::repo::{MutableRepo, ReadonlyRepo, RepoLoadError, RepoLoader}; +use jujutsu_lib::repo::{MutableRepo, ReadonlyRepo, RepoInitError, RepoLoadError, RepoLoader}; use jujutsu_lib::repo_path::RepoPath; use jujutsu_lib::revset::{RevsetError, RevsetParseError}; use jujutsu_lib::revset_graph_iterator::RevsetGraphEdgeType; @@ -87,6 +87,12 @@ impl From for CommandError { } } +impl From for CommandError { + fn from(_: RepoInitError) -> Self { + CommandError::UserError("The target repo already exists".to_string()) + } +} + impl From for CommandError { fn from(err: DiffEditError) -> Self { CommandError::UserError(format!("Failed to edit diff: {}", err)) @@ -785,7 +791,7 @@ fn cmd_init( let repo = if let Some(git_store_str) = sub_matches.value_of("git-store") { let git_store_path = ui.cwd().join(git_store_str); - let repo = ReadonlyRepo::init_external_git(ui.settings(), wc_path, git_store_path); + let repo = ReadonlyRepo::init_external_git(ui.settings(), wc_path, git_store_path)?; let git_repo = repo.store().git_repo().unwrap(); let mut tx = repo.start_transaction("import git refs"); git::import_refs(tx.mut_repo(), &git_repo).unwrap(); @@ -793,9 +799,9 @@ fn cmd_init( // number. tx.commit() } else if sub_matches.is_present("git") { - ReadonlyRepo::init_internal_git(ui.settings(), wc_path) + ReadonlyRepo::init_internal_git(ui.settings(), wc_path)? } else { - ReadonlyRepo::init_local(ui.settings(), wc_path) + ReadonlyRepo::init_local(ui.settings(), wc_path)? }; writeln!( ui, @@ -2293,7 +2299,7 @@ fn cmd_git_clone( fs::create_dir(&wc_path).unwrap(); } - let repo = ReadonlyRepo::init_internal_git(ui.settings(), wc_path); + let repo = ReadonlyRepo::init_internal_git(ui.settings(), wc_path)?; let git_repo = get_git_repo(repo.store())?; writeln!( ui,