rust/hg-core/src/repo.rs
changeset 46462 d03b0601e0eb
parent 46446 1dcd9c9975ed
child 46463 95b276283b67
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<'_> {