rust/hg-core/src/repo.rs
branchstable
changeset 47779 cf5f8da2244c
parent 47674 ff97e793ed36
child 47977 696abab107b4
equal deleted inserted replaced
47778:6df528ed47a9 47779:cf5f8da2244c
     4 use crate::requirements;
     4 use crate::requirements;
     5 use crate::utils::files::get_path_from_bytes;
     5 use crate::utils::files::get_path_from_bytes;
     6 use crate::utils::SliceExt;
     6 use crate::utils::SliceExt;
     7 use memmap::{Mmap, MmapOptions};
     7 use memmap::{Mmap, MmapOptions};
     8 use std::collections::HashSet;
     8 use std::collections::HashSet;
       
     9 use std::io::ErrorKind;
     9 use std::path::{Path, PathBuf};
    10 use std::path::{Path, PathBuf};
    10 
    11 
    11 /// A repository on disk
    12 /// A repository on disk
    12 pub struct Repo {
    13 pub struct Repo {
    13     working_directory: PathBuf,
    14     working_directory: PathBuf,
    49     pub fn find_repo_root() -> Result<PathBuf, RepoError> {
    50     pub fn find_repo_root() -> Result<PathBuf, RepoError> {
    50         let current_directory = crate::utils::current_dir()?;
    51         let current_directory = crate::utils::current_dir()?;
    51         // ancestors() is inclusive: it first yields `current_directory`
    52         // ancestors() is inclusive: it first yields `current_directory`
    52         // as-is.
    53         // as-is.
    53         for ancestor in current_directory.ancestors() {
    54         for ancestor in current_directory.ancestors() {
    54             if ancestor.join(".hg").is_dir() {
    55             if is_dir(ancestor.join(".hg"))? {
    55                 return Ok(ancestor.to_path_buf());
    56                 return Ok(ancestor.to_path_buf());
    56             }
    57             }
    57         }
    58         }
    58         return Err(RepoError::NotFound {
    59         return Err(RepoError::NotFound {
    59             at: current_directory,
    60             at: current_directory,
    71     pub fn find(
    72     pub fn find(
    72         config: &Config,
    73         config: &Config,
    73         explicit_path: Option<PathBuf>,
    74         explicit_path: Option<PathBuf>,
    74     ) -> Result<Self, RepoError> {
    75     ) -> Result<Self, RepoError> {
    75         if let Some(root) = explicit_path {
    76         if let Some(root) = explicit_path {
    76             if root.join(".hg").is_dir() {
    77             if is_dir(root.join(".hg"))? {
    77                 Self::new_at_path(root.to_owned(), config)
    78                 Self::new_at_path(root.to_owned(), config)
    78             } else if root.is_file() {
    79             } else if is_file(&root)? {
    79                 Err(HgError::unsupported("bundle repository").into())
    80                 Err(HgError::unsupported("bundle repository").into())
    80             } else {
    81             } else {
    81                 Err(RepoError::NotFound {
    82                 Err(RepoError::NotFound {
    82                     at: root.to_owned(),
    83                     at: root.to_owned(),
    83                 })
    84                 })
   128             let mut shared_path =
   129             let mut shared_path =
   129                 get_path_from_bytes(bytes.trim_end_newlines()).to_owned();
   130                 get_path_from_bytes(bytes.trim_end_newlines()).to_owned();
   130             if relative {
   131             if relative {
   131                 shared_path = dot_hg.join(shared_path)
   132                 shared_path = dot_hg.join(shared_path)
   132             }
   133             }
   133             if !shared_path.is_dir() {
   134             if !is_dir(&shared_path)? {
   134                 return Err(HgError::corrupted(format!(
   135                 return Err(HgError::corrupted(format!(
   135                     ".hg/sharedpath points to nonexistent directory {}",
   136                     ".hg/sharedpath points to nonexistent directory {}",
   136                     shared_path.display()
   137                     shared_path.display()
   137                 ))
   138                 ))
   138                 .into());
   139                 .into());
   284         let to = self.join(relative_to);
   285         let to = self.join(relative_to);
   285         std::fs::rename(&from, &to)
   286         std::fs::rename(&from, &to)
   286             .with_context(|| IoErrorContext::RenamingFile { from, to })
   287             .with_context(|| IoErrorContext::RenamingFile { from, to })
   287     }
   288     }
   288 }
   289 }
       
   290 
       
   291 fn fs_metadata(
       
   292     path: impl AsRef<Path>,
       
   293 ) -> Result<Option<std::fs::Metadata>, HgError> {
       
   294     let path = path.as_ref();
       
   295     match std::fs::metadata(path) {
       
   296         Ok(meta) => Ok(Some(meta)),
       
   297         Err(error) => match error.kind() {
       
   298             // TODO: when we require a Rust version where `NotADirectory` is
       
   299             // stable, invert this logic and return None for it and `NotFound`
       
   300             // and propagate any other error.
       
   301             ErrorKind::PermissionDenied => Err(error).with_context(|| {
       
   302                 IoErrorContext::ReadingMetadata(path.to_owned())
       
   303             }),
       
   304             _ => Ok(None),
       
   305         },
       
   306     }
       
   307 }
       
   308 
       
   309 fn is_dir(path: impl AsRef<Path>) -> Result<bool, HgError> {
       
   310     Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_dir()))
       
   311 }
       
   312 
       
   313 fn is_file(path: impl AsRef<Path>) -> Result<bool, HgError> {
       
   314     Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_file()))
       
   315 }