rust/hg-core/src/repo.rs
changeset 46486 d7685105e504
parent 46485 f031fe1c6ede
child 46503 d8730ff51d5a
equal deleted inserted replaced
46485:f031fe1c6ede 46486:d7685105e504
     1 use crate::config::Config;
     1 use crate::config::{Config, ConfigError, ConfigParseError};
     2 use crate::errors::{HgError, IoResultExt};
     2 use crate::errors::{HgError, IoResultExt};
     3 use crate::requirements;
     3 use crate::requirements;
     4 use crate::utils::files::get_path_from_bytes;
     4 use crate::utils::files::get_path_from_bytes;
     5 use memmap::{Mmap, MmapOptions};
     5 use memmap::{Mmap, MmapOptions};
     6 use std::collections::HashSet;
     6 use std::collections::HashSet;
    10 pub struct Repo {
    10 pub struct Repo {
    11     working_directory: PathBuf,
    11     working_directory: PathBuf,
    12     dot_hg: PathBuf,
    12     dot_hg: PathBuf,
    13     store: PathBuf,
    13     store: PathBuf,
    14     requirements: HashSet<String>,
    14     requirements: HashSet<String>,
       
    15     config: Config,
    15 }
    16 }
    16 
    17 
    17 #[derive(Debug, derive_more::From)]
    18 #[derive(Debug, derive_more::From)]
    18 pub enum RepoFindError {
    19 pub enum RepoError {
    19     NotFoundInCurrentDirectoryOrAncestors {
    20     NotFound {
    20         current_directory: PathBuf,
    21         current_directory: PathBuf,
    21     },
    22     },
    22     #[from]
    23     #[from]
       
    24     ConfigParseError(ConfigParseError),
       
    25     #[from]
    23     Other(HgError),
    26     Other(HgError),
       
    27 }
       
    28 
       
    29 impl From<ConfigError> for RepoError {
       
    30     fn from(error: ConfigError) -> Self {
       
    31         match error {
       
    32             ConfigError::Parse(error) => error.into(),
       
    33             ConfigError::Other(error) => error.into(),
       
    34         }
       
    35     }
    24 }
    36 }
    25 
    37 
    26 /// Filesystem access abstraction for the contents of a given "base" diretory
    38 /// Filesystem access abstraction for the contents of a given "base" diretory
    27 #[derive(Clone, Copy)]
    39 #[derive(Clone, Copy)]
    28 pub(crate) struct Vfs<'a> {
    40 pub(crate) struct Vfs<'a> {
    30 }
    42 }
    31 
    43 
    32 impl Repo {
    44 impl Repo {
    33     /// Search the current directory and its ancestores for a repository:
    45     /// Search the current directory and its ancestores for a repository:
    34     /// a working directory that contains a `.hg` sub-directory.
    46     /// a working directory that contains a `.hg` sub-directory.
    35     pub fn find(config: &Config) -> Result<Self, RepoFindError> {
    47     pub fn find(config: &Config) -> Result<Self, RepoError> {
    36         let current_directory = crate::utils::current_dir()?;
    48         let current_directory = crate::utils::current_dir()?;
    37         // ancestors() is inclusive: it first yields `current_directory` as-is.
    49         // ancestors() is inclusive: it first yields `current_directory` as-is.
    38         for ancestor in current_directory.ancestors() {
    50         for ancestor in current_directory.ancestors() {
    39             if ancestor.join(".hg").is_dir() {
    51             if ancestor.join(".hg").is_dir() {
    40                 return Ok(Self::new_at_path(ancestor.to_owned(), config)?);
    52                 return Ok(Self::new_at_path(ancestor.to_owned(), config)?);
    41             }
    53             }
    42         }
    54         }
    43         Err(RepoFindError::NotFoundInCurrentDirectoryOrAncestors {
    55         Err(RepoError::NotFound { current_directory })
    44             current_directory,
       
    45         })
       
    46     }
    56     }
    47 
    57 
    48     /// To be called after checking that `.hg` is a sub-directory
    58     /// To be called after checking that `.hg` is a sub-directory
    49     fn new_at_path(
    59     fn new_at_path(
    50         working_directory: PathBuf,
    60         working_directory: PathBuf,
    51         config: &Config,
    61         config: &Config,
    52     ) -> Result<Self, HgError> {
    62     ) -> Result<Self, RepoError> {
    53         let dot_hg = working_directory.join(".hg");
    63         let dot_hg = working_directory.join(".hg");
       
    64 
       
    65         let mut repo_config_files = Vec::new();
       
    66         repo_config_files.push(dot_hg.join("hgrc"));
       
    67         repo_config_files.push(dot_hg.join("hgrc-not-shared"));
    54 
    68 
    55         let hg_vfs = Vfs { base: &dot_hg };
    69         let hg_vfs = Vfs { base: &dot_hg };
    56         let mut reqs = requirements::load_if_exists(hg_vfs)?;
    70         let mut reqs = requirements::load_if_exists(hg_vfs)?;
    57         let relative =
    71         let relative =
    58             reqs.contains(requirements::RELATIVE_SHARED_REQUIREMENT);
    72             reqs.contains(requirements::RELATIVE_SHARED_REQUIREMENT);
    87             }
   101             }
    88             if !shared_path.is_dir() {
   102             if !shared_path.is_dir() {
    89                 return Err(HgError::corrupted(format!(
   103                 return Err(HgError::corrupted(format!(
    90                     ".hg/sharedpath points to nonexistent directory {}",
   104                     ".hg/sharedpath points to nonexistent directory {}",
    91                     shared_path.display()
   105                     shared_path.display()
    92                 )));
   106                 ))
       
   107                 .into());
    93             }
   108             }
    94 
   109 
    95             store_path = shared_path.join("store");
   110             store_path = shared_path.join("store");
    96 
   111 
    97             let source_is_share_safe =
   112             let source_is_share_safe =
    98                 requirements::load(Vfs { base: &shared_path })?
   113                 requirements::load(Vfs { base: &shared_path })?
    99                     .contains(requirements::SHARESAFE_REQUIREMENT);
   114                     .contains(requirements::SHARESAFE_REQUIREMENT);
   100 
   115 
   101             if share_safe && !source_is_share_safe {
   116             if share_safe && !source_is_share_safe {
   102                 return Err(match config.get(b"safe-mismatch", b"source-not-safe") {
   117                 return Err(match config
       
   118                     .get(b"safe-mismatch", b"source-not-safe")
       
   119                 {
   103                     Some(b"abort") | None => HgError::abort(
   120                     Some(b"abort") | None => HgError::abort(
   104                         "share source does not support share-safe requirement"
   121                         "share source does not support share-safe requirement",
   105                     ),
   122                     ),
   106                     _ => HgError::unsupported("share-safe downgrade")
   123                     _ => HgError::unsupported("share-safe downgrade"),
   107                 });
   124                 }
       
   125                 .into());
   108             } else if source_is_share_safe && !share_safe {
   126             } else if source_is_share_safe && !share_safe {
   109                 return Err(
   127                 return Err(
   110                     match config.get(b"safe-mismatch", b"source-safe") {
   128                     match config.get(b"safe-mismatch", b"source-safe") {
   111                         Some(b"abort") | None => HgError::abort(
   129                         Some(b"abort") | None => HgError::abort(
   112                             "version mismatch: source uses share-safe \
   130                             "version mismatch: source uses share-safe \
   113                             functionality while the current share does not",
   131                             functionality while the current share does not",
   114                         ),
   132                         ),
   115                         _ => HgError::unsupported("share-safe upgrade"),
   133                         _ => HgError::unsupported("share-safe upgrade"),
   116                     },
   134                     }
       
   135                     .into(),
   117                 );
   136                 );
   118             }
   137             }
   119         }
   138 
       
   139             if share_safe {
       
   140                 repo_config_files.insert(0, shared_path.join("hgrc"))
       
   141             }
       
   142         }
       
   143 
       
   144         let repo_config = config.combine_with_repo(&repo_config_files)?;
   120 
   145 
   121         let repo = Self {
   146         let repo = Self {
   122             requirements: reqs,
   147             requirements: reqs,
   123             working_directory,
   148             working_directory,
   124             store: store_path,
   149             store: store_path,
   125             dot_hg,
   150             dot_hg,
       
   151             config: repo_config,
   126         };
   152         };
   127 
   153 
   128         requirements::check(&repo)?;
   154         requirements::check(&repo)?;
   129 
   155 
   130         Ok(repo)
   156         Ok(repo)
   134         &self.working_directory
   160         &self.working_directory
   135     }
   161     }
   136 
   162 
   137     pub fn requirements(&self) -> &HashSet<String> {
   163     pub fn requirements(&self) -> &HashSet<String> {
   138         &self.requirements
   164         &self.requirements
       
   165     }
       
   166 
       
   167     pub fn config(&self) -> &Config {
       
   168         &self.config
   139     }
   169     }
   140 
   170 
   141     /// For accessing repository files (in `.hg`), except for the store
   171     /// For accessing repository files (in `.hg`), except for the store
   142     /// (`.hg/store`).
   172     /// (`.hg/store`).
   143     pub(crate) fn hg_vfs(&self) -> Vfs<'_> {
   173     pub(crate) fn hg_vfs(&self) -> Vfs<'_> {