comparison rust/hg-core/src/repo.rs @ 46462:d03b0601e0eb

rhg: initial support for shared repositories Differential Revision: https://phab.mercurial-scm.org/D9941
author Simon Sapin <simon.sapin@octobus.net>
date Thu, 14 Jan 2021 13:04:12 +0100
parents 1dcd9c9975ed
children 95b276283b67
comparison
equal deleted inserted replaced
46461:f3f4d1b7dc97 46462:d03b0601e0eb
1 use crate::errors::{HgError, IoResultExt}; 1 use crate::errors::{HgError, IoResultExt};
2 use crate::requirements; 2 use crate::requirements;
3 use crate::utils::files::get_path_from_bytes;
3 use memmap::{Mmap, MmapOptions}; 4 use memmap::{Mmap, MmapOptions};
5 use std::collections::HashSet;
4 use std::path::{Path, PathBuf}; 6 use std::path::{Path, PathBuf};
5 7
6 /// A repository on disk 8 /// A repository on disk
7 pub struct Repo { 9 pub struct Repo {
8 working_directory: PathBuf, 10 working_directory: PathBuf,
9 dot_hg: PathBuf, 11 dot_hg: PathBuf,
10 store: PathBuf, 12 store: PathBuf,
13 requirements: HashSet<String>,
11 } 14 }
12 15
13 #[derive(Debug, derive_more::From)] 16 #[derive(Debug, derive_more::From)]
14 pub enum RepoFindError { 17 pub enum RepoFindError {
15 NotFoundInCurrentDirectoryOrAncestors { 18 NotFoundInCurrentDirectoryOrAncestors {
30 /// a working directory that contains a `.hg` sub-directory. 33 /// a working directory that contains a `.hg` sub-directory.
31 pub fn find() -> Result<Self, RepoFindError> { 34 pub fn find() -> Result<Self, RepoFindError> {
32 let current_directory = crate::utils::current_dir()?; 35 let current_directory = crate::utils::current_dir()?;
33 // ancestors() is inclusive: it first yields `current_directory` as-is. 36 // ancestors() is inclusive: it first yields `current_directory` as-is.
34 for ancestor in current_directory.ancestors() { 37 for ancestor in current_directory.ancestors() {
35 let dot_hg = ancestor.join(".hg"); 38 if ancestor.join(".hg").is_dir() {
36 if dot_hg.is_dir() { 39 return Ok(Self::new_at_path(ancestor.to_owned())?);
37 let repo = Self {
38 store: dot_hg.join("store"),
39 dot_hg,
40 working_directory: ancestor.to_owned(),
41 };
42 requirements::check(&repo)?;
43 return Ok(repo);
44 } 40 }
45 } 41 }
46 Err(RepoFindError::NotFoundInCurrentDirectoryOrAncestors { 42 Err(RepoFindError::NotFoundInCurrentDirectoryOrAncestors {
47 current_directory, 43 current_directory,
48 }) 44 })
49 } 45 }
50 46
47 /// To be called after checking that `.hg` is a sub-directory
48 fn new_at_path(working_directory: PathBuf) -> Result<Self, HgError> {
49 let dot_hg = working_directory.join(".hg");
50 let hg_vfs = Vfs { base: &dot_hg };
51 let reqs = requirements::load_if_exists(hg_vfs)?;
52 let relative =
53 reqs.contains(requirements::RELATIVE_SHARED_REQUIREMENT);
54 let shared =
55 reqs.contains(requirements::SHARED_REQUIREMENT) || relative;
56 let store_path;
57 if !shared {
58 store_path = dot_hg.join("store");
59 } else {
60 let bytes = hg_vfs.read("sharedpath")?;
61 let mut shared_path = get_path_from_bytes(&bytes).to_owned();
62 if relative {
63 shared_path = dot_hg.join(shared_path)
64 }
65 if !shared_path.is_dir() {
66 return Err(HgError::corrupted(format!(
67 ".hg/sharedpath points to nonexistent directory {}",
68 shared_path.display()
69 )));
70 }
71
72 store_path = shared_path.join("store");
73 }
74
75 let repo = Self {
76 requirements: reqs,
77 working_directory,
78 store: store_path,
79 dot_hg,
80 };
81
82 requirements::check(&repo)?;
83
84 Ok(repo)
85 }
86
51 pub fn working_directory_path(&self) -> &Path { 87 pub fn working_directory_path(&self) -> &Path {
52 &self.working_directory 88 &self.working_directory
89 }
90
91 pub fn requirements(&self) -> &HashSet<String> {
92 &self.requirements
53 } 93 }
54 94
55 /// For accessing repository files (in `.hg`), except for the store 95 /// For accessing repository files (in `.hg`), except for the store
56 /// (`.hg/store`). 96 /// (`.hg/store`).
57 pub(crate) fn hg_vfs(&self) -> Vfs<'_> { 97 pub(crate) fn hg_vfs(&self) -> Vfs<'_> {