forked from mirrors/jj
repo: make .jj/store a directory also in Git-backed repos
I think this is just cleaner, and it gives us room to put other store-related data in the `.jj/store/` directory. I may want to use that place for writing the metadata we currently write in Git notes (#7).
This commit is contained in:
parent
dba72af857
commit
1b6efdc3f8
3 changed files with 58 additions and 38 deletions
|
@ -16,7 +16,7 @@ use std::collections::{HashMap, HashSet};
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::{Read, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::{Arc, Mutex, MutexGuard};
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
|
|
||||||
|
@ -141,9 +141,7 @@ impl ReadonlyRepo {
|
||||||
wc_path: PathBuf,
|
wc_path: PathBuf,
|
||||||
) -> Result<Arc<ReadonlyRepo>, RepoInitError> {
|
) -> Result<Arc<ReadonlyRepo>, RepoInitError> {
|
||||||
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 backend = Box::new(LocalBackend::init(repo_path.join("store")));
|
||||||
fs::create_dir(&store_path).unwrap();
|
|
||||||
let backend = Box::new(LocalBackend::init(store_path));
|
|
||||||
Ok(ReadonlyRepo::init(settings, repo_path, wc_path, backend))
|
Ok(ReadonlyRepo::init(settings, repo_path, wc_path, backend))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,13 +151,12 @@ impl ReadonlyRepo {
|
||||||
wc_path: PathBuf,
|
wc_path: PathBuf,
|
||||||
) -> Result<Arc<ReadonlyRepo>, RepoInitError> {
|
) -> Result<Arc<ReadonlyRepo>, RepoInitError> {
|
||||||
let repo_path = ReadonlyRepo::init_repo_dir(&wc_path)?;
|
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");
|
let store_path = repo_path.join("store");
|
||||||
let git_store_path = fs::canonicalize(git_store_path).unwrap();
|
let git_repo_path = store_path.join("git");
|
||||||
let mut store_file = File::create(store_path).unwrap();
|
git2::Repository::init_bare(&git_repo_path).unwrap();
|
||||||
store_file.write_all(b"git: git").unwrap();
|
let mut git_target_file = File::create(store_path.join("git_target")).unwrap();
|
||||||
let backend = Box::new(GitBackend::load(&git_store_path));
|
git_target_file.write_all(b"git").unwrap();
|
||||||
|
let backend = Box::new(GitBackend::load(&git_repo_path));
|
||||||
Ok(ReadonlyRepo::init(settings, repo_path, wc_path, backend))
|
Ok(ReadonlyRepo::init(settings, repo_path, wc_path, backend))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,12 +168,12 @@ impl ReadonlyRepo {
|
||||||
) -> Result<Arc<ReadonlyRepo>, RepoInitError> {
|
) -> Result<Arc<ReadonlyRepo>, RepoInitError> {
|
||||||
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");
|
||||||
let git_store_path = fs::canonicalize(git_store_path).unwrap();
|
let git_repo_path = fs::canonicalize(git_store_path).unwrap();
|
||||||
let mut store_file = File::create(store_path).unwrap();
|
let mut git_target_file = File::create(store_path.join("git_target")).unwrap();
|
||||||
store_file
|
git_target_file
|
||||||
.write_all(format!("git: {}", git_store_path.to_str().unwrap()).as_bytes())
|
.write_all(git_repo_path.to_str().unwrap().as_bytes())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let backend = Box::new(GitBackend::load(&git_store_path));
|
let backend = Box::new(GitBackend::load(&git_repo_path));
|
||||||
Ok(ReadonlyRepo::init(settings, repo_path, wc_path, backend))
|
Ok(ReadonlyRepo::init(settings, repo_path, wc_path, backend))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,6 +183,7 @@ impl ReadonlyRepo {
|
||||||
Err(RepoInitError::DestinationExists(repo_path))
|
Err(RepoInitError::DestinationExists(repo_path))
|
||||||
} else {
|
} else {
|
||||||
fs::create_dir(&repo_path).unwrap();
|
fs::create_dir(&repo_path).unwrap();
|
||||||
|
fs::create_dir(repo_path.join("store")).unwrap();
|
||||||
fs::create_dir(repo_path.join("working_copy")).unwrap();
|
fs::create_dir(repo_path.join("working_copy")).unwrap();
|
||||||
fs::create_dir(repo_path.join("view")).unwrap();
|
fs::create_dir(repo_path.join("view")).unwrap();
|
||||||
fs::create_dir(repo_path.join("op_store")).unwrap();
|
fs::create_dir(repo_path.join("op_store")).unwrap();
|
||||||
|
@ -400,7 +398,26 @@ 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 = Store::load_store(&repo_path);
|
let store_path = repo_path.join("store");
|
||||||
|
if store_path.is_file() {
|
||||||
|
// This is the old format. Let's be nice and upgrade any existing repos.
|
||||||
|
// TODO: Delete this in early 2022 or so
|
||||||
|
println!("The repo format has changed. Upgrading...");
|
||||||
|
let mut buf = vec![];
|
||||||
|
{
|
||||||
|
let mut store_file = File::open(&store_path).unwrap();
|
||||||
|
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();
|
||||||
|
fs::remove_file(&store_path).unwrap();
|
||||||
|
fs::create_dir(&store_path).unwrap();
|
||||||
|
fs::rename(repo_path.join("git"), store_path.join("git")).unwrap();
|
||||||
|
fs::write(store_path.join("git_target"), &git_backend_path_str).unwrap();
|
||||||
|
println!("Done. .jj/git is now .jj/store/git");
|
||||||
|
}
|
||||||
|
let store = Store::load_store(repo_path.join("store"));
|
||||||
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")));
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::PathBuf;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use crate::backend;
|
use crate::backend;
|
||||||
|
@ -51,25 +51,20 @@ impl Store {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_store(repo_path: &Path) -> Arc<Store> {
|
pub fn load_store(store_path: PathBuf) -> Arc<Store> {
|
||||||
let store_path = repo_path.join("store");
|
|
||||||
let backend: Box<dyn Backend>;
|
let backend: Box<dyn Backend>;
|
||||||
// TODO: Perhaps .jj/store should always be a directory. Then .jj/git would live
|
let git_target_path = store_path.join("git_target");
|
||||||
// inside that directory and this function would not need to know the repo path
|
if git_target_path.is_file() {
|
||||||
// (only the store path). Maybe there would be a .jj/store/format file
|
let mut git_target_file = File::open(git_target_path).unwrap();
|
||||||
// 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();
|
let mut buf = Vec::new();
|
||||||
store_file.read_to_end(&mut buf).unwrap();
|
git_target_file.read_to_end(&mut buf).unwrap();
|
||||||
let contents = String::from_utf8(buf).unwrap();
|
let git_backend_path_str = String::from_utf8(buf).unwrap();
|
||||||
assert!(contents.starts_with("git: "));
|
|
||||||
let git_backend_path_str = contents[5..].to_string();
|
|
||||||
let git_backend_path =
|
let git_backend_path =
|
||||||
std::fs::canonicalize(repo_path.join(PathBuf::from(git_backend_path_str))).unwrap();
|
std::fs::canonicalize(store_path.join(PathBuf::from(git_backend_path_str)))
|
||||||
|
.unwrap();
|
||||||
backend = Box::new(GitBackend::load(&git_backend_path));
|
backend = Box::new(GitBackend::load(&git_backend_path));
|
||||||
|
} else {
|
||||||
|
backend = Box::new(LocalBackend::load(store_path));
|
||||||
}
|
}
|
||||||
Store::new(backend)
|
Store::new(backend)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,16 @@ fn test_init_git_internal() {
|
||||||
let repo_path = temp_dir.path().join("repo");
|
let repo_path = temp_dir.path().join("repo");
|
||||||
assert!(repo_path.is_dir());
|
assert!(repo_path.is_dir());
|
||||||
assert!(repo_path.join(".jj").is_dir());
|
assert!(repo_path.join(".jj").is_dir());
|
||||||
assert!(repo_path.join(".jj").join("git").is_dir());
|
assert!(repo_path.join(".jj").join("store").is_dir());
|
||||||
let store_file_contents = std::fs::read_to_string(repo_path.join(".jj").join("store")).unwrap();
|
assert!(repo_path.join(".jj").join("store").join("git").is_dir());
|
||||||
assert_eq!(store_file_contents, "git: git");
|
assert!(repo_path
|
||||||
|
.join(".jj")
|
||||||
|
.join("store")
|
||||||
|
.join("git_target")
|
||||||
|
.is_file());
|
||||||
|
let git_target_file_contents =
|
||||||
|
std::fs::read_to_string(repo_path.join(".jj").join("store").join("git_target")).unwrap();
|
||||||
|
assert_eq!(git_target_file_contents, "git");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
output.stdout_string(),
|
output.stdout_string(),
|
||||||
format!("Initialized repo in \"{}\"\n", repo_path.to_str().unwrap())
|
format!("Initialized repo in \"{}\"\n", repo_path.to_str().unwrap())
|
||||||
|
@ -49,9 +56,10 @@ fn test_init_git_external() {
|
||||||
let repo_path = temp_dir.path().join("repo");
|
let repo_path = temp_dir.path().join("repo");
|
||||||
assert!(repo_path.is_dir());
|
assert!(repo_path.is_dir());
|
||||||
assert!(repo_path.join(".jj").is_dir());
|
assert!(repo_path.join(".jj").is_dir());
|
||||||
let store_file_contents = std::fs::read_to_string(repo_path.join(".jj").join("store")).unwrap();
|
assert!(repo_path.join(".jj").join("store").is_dir());
|
||||||
assert!(store_file_contents.starts_with("git: "));
|
let git_target_file_contents =
|
||||||
assert!(store_file_contents
|
std::fs::read_to_string(repo_path.join(".jj").join("store").join("git_target")).unwrap();
|
||||||
|
assert!(git_target_file_contents
|
||||||
.replace('\\', "/")
|
.replace('\\', "/")
|
||||||
.ends_with("/git-repo"));
|
.ends_with("/git-repo"));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
Loading…
Reference in a new issue