diff --git a/lib/src/repo.rs b/lib/src/repo.rs index 20e9d85d8..ac2f63d95 100644 --- a/lib/src/repo.rs +++ b/lib/src/repo.rs @@ -91,7 +91,22 @@ impl ReadonlyRepo { ReadonlyRepo::init(settings, repo_path, wc_path, store) } - pub fn init_git( + /// 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(); + let git_store_path = repo_path.join("git"); + git2::Repository::init_bare(&git_store_path).unwrap(); + 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(); + 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) + } + + /// Initializes a repo with an existing Git store at the specified path + pub fn init_external_git( settings: &UserSettings, wc_path: PathBuf, git_store_path: PathBuf, @@ -102,7 +117,7 @@ impl ReadonlyRepo { let git_store_path = fs::canonicalize(git_store_path).unwrap(); let mut store_file = File::create(store_path).unwrap(); store_file - .write_all((String::from("git: ") + git_store_path.to_str().unwrap()).as_bytes()) + .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) @@ -183,7 +198,8 @@ impl ReadonlyRepo { 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 = PathBuf::from(git_store_path_str); + let git_store_path = + fs::canonicalize(repo_path.join(PathBuf::from(git_store_path_str))).unwrap(); store = Box::new(GitStore::load(git_store_path)); } let store = StoreWrapper::new(store); diff --git a/lib/src/testutils.rs b/lib/src/testutils.rs index 49b448339..0ddc1a4a9 100644 --- a/lib/src/testutils.rs +++ b/lib/src/testutils.rs @@ -44,7 +44,7 @@ pub fn init_repo(settings: &UserSettings, use_git: bool) -> (TempDir, Arc PushTestSet create_repo_clone(&source_repo_dir, &clone_repo_dir); std::fs::create_dir(&jj_repo_dir).unwrap(); let mut jj_repo = - ReadonlyRepo::init_git(&settings, jj_repo_dir.clone(), clone_repo_dir.clone()); + ReadonlyRepo::init_external_git(&settings, jj_repo_dir.clone(), clone_repo_dir.clone()); let new_commit = testutils::create_random_commit(&settings, &jj_repo) .set_parents(vec![initial_commit_id.clone()]) .write_to_new_transaction(&jj_repo, "test"); diff --git a/lib/tests/test_init.rs b/lib/tests/test_init.rs new file mode 100644 index 000000000..b07786d2a --- /dev/null +++ b/lib/tests/test_init.rs @@ -0,0 +1,67 @@ +// 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 jj_lib::repo::ReadonlyRepo; +use jj_lib::testutils; + +#[test] +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()); + assert!(repo.store().git_repo().is_none()); + assert_eq!(repo.working_copy_path(), &wc_path); + assert_eq!(repo.repo_path(), &wc_path.join(".jj")); + + // Just test that we write a commit to the store + let mut tx = repo.start_transaction("test"); + testutils::create_random_commit(&settings, &repo).write_to_transaction(&mut tx); + tx.discard(); +} + +#[test] +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()); + assert!(repo.store().git_repo().is_some()); + assert_eq!(repo.working_copy_path(), &wc_path); + assert_eq!(repo.repo_path(), &wc_path.join(".jj")); + + // Just test that we write a commit to the store + let mut tx = repo.start_transaction("test"); + testutils::create_random_commit(&settings, &repo).write_to_transaction(&mut tx); + tx.discard(); +} + +#[test] +fn test_init_external_git() { + let settings = testutils::user_settings(); + let temp_dir = tempfile::tempdir().unwrap(); + let git_repo_path = temp_dir.path().join("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); + assert!(repo.store().git_repo().is_some()); + assert_eq!(repo.working_copy_path(), &wc_path); + assert_eq!(repo.repo_path(), &wc_path.join(".jj")); + + // Just test that we write a commit to the store + let mut tx = repo.start_transaction("test"); + testutils::create_random_commit(&settings, &repo).write_to_transaction(&mut tx); + tx.discard(); +} diff --git a/src/commands.rs b/src/commands.rs index c700f5e8a..e6d0908c5 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -270,6 +270,7 @@ fn get_app<'a, 'b>() -> App<'a, 'b> { let init_command = SubCommand::with_name("init") .about("initialize a repo") .arg(Arg::with_name("destination").index(1).default_value(".")) + .arg(Arg::with_name("git").long("git")) .arg( Arg::with_name("git-store") .long("git-store") @@ -541,6 +542,11 @@ fn cmd_init( _matches: &ArgMatches, sub_matches: &ArgMatches, ) -> Result<(), CommandError> { + if sub_matches.is_present("git") && sub_matches.is_present("git-store") { + return Err(CommandError::UserError(String::from( + "--git cannot be used with --git-store", + ))); + } let wc_path_str = sub_matches.value_of("destination").unwrap(); let wc_path = ui.cwd().join(wc_path_str); if wc_path.exists() { @@ -552,7 +558,9 @@ 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); - repo = ReadonlyRepo::init_git(ui.settings(), wc_path, git_store_path); + repo = ReadonlyRepo::init_external_git(ui.settings(), wc_path, git_store_path); + } else if sub_matches.is_present("git") { + repo = ReadonlyRepo::init_internal_git(ui.settings(), wc_path); } else { repo = ReadonlyRepo::init_local(ui.settings(), wc_path); } diff --git a/tests/test_init_command.rs b/tests/test_init_command.rs index 58256f9b6..5d06eeb52 100644 --- a/tests/test_init_command.rs +++ b/tests/test_init_command.rs @@ -15,7 +15,25 @@ use jj::testutils; #[test] -fn test_init_git() { +fn test_init_git_internal() { + let temp_dir = tempfile::tempdir().unwrap(); + let output = testutils::CommandRunner::new(temp_dir.path()).run(vec!["init", "repo", "--git"]); + assert_eq!(output.status, 0); + + let repo_path = temp_dir.path().join("repo"); + assert!(repo_path.is_dir()); + assert!(repo_path.join(".jj").is_dir()); + assert!(repo_path.join(".jj").join("git").is_dir()); + let store_file_contents = std::fs::read_to_string(repo_path.join(".jj").join("store")).unwrap(); + assert_eq!(store_file_contents, "git: git"); + assert_eq!( + output.stdout_string(), + format!("Initialized repo in \"{}\"\n", repo_path.to_str().unwrap()) + ); +} + +#[test] +fn test_init_git_external() { let temp_dir = tempfile::tempdir().unwrap(); let git_repo_path = temp_dir.path().join("git-repo"); git2::Repository::init(git_repo_path.clone()).unwrap();