rust/hg-core/src/repo.rs
changeset 47980 9cd35c8c6044
parent 47977 696abab107b4
child 47984 81aedf1fc897
equal deleted inserted replaced
47979:cff41e168c25 47980:9cd35c8c6044
     1 use crate::config::{Config, ConfigError, ConfigParseError};
     1 use crate::config::{Config, ConfigError, ConfigParseError};
     2 use crate::errors::{HgError, IoErrorContext, IoResultExt};
     2 use crate::errors::HgError;
     3 use crate::exit_codes;
     3 use crate::exit_codes;
     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 crate::vfs::{is_dir, is_file, Vfs};
     8 use std::collections::HashSet;
     8 use std::collections::HashSet;
     9 use std::io::ErrorKind;
       
    10 use std::path::{Path, PathBuf};
     9 use std::path::{Path, PathBuf};
    11 
    10 
    12 /// A repository on disk
    11 /// A repository on disk
    13 pub struct Repo {
    12 pub struct Repo {
    14     working_directory: PathBuf,
    13     working_directory: PathBuf,
    34         match error {
    33         match error {
    35             ConfigError::Parse(error) => error.into(),
    34             ConfigError::Parse(error) => error.into(),
    36             ConfigError::Other(error) => error.into(),
    35             ConfigError::Other(error) => error.into(),
    37         }
    36         }
    38     }
    37     }
    39 }
       
    40 
       
    41 /// Filesystem access abstraction for the contents of a given "base" diretory
       
    42 #[derive(Clone, Copy)]
       
    43 pub struct Vfs<'a> {
       
    44     pub(crate) base: &'a Path,
       
    45 }
    38 }
    46 
    39 
    47 impl Repo {
    40 impl Repo {
    48     /// tries to find nearest repository root in current working directory or
    41     /// tries to find nearest repository root in current working directory or
    49     /// its ancestors
    42     /// its ancestors
   249                 .clone()
   242                 .clone()
   250         };
   243         };
   251         Ok(parents)
   244         Ok(parents)
   252     }
   245     }
   253 }
   246 }
   254 
       
   255 impl Vfs<'_> {
       
   256     pub fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf {
       
   257         self.base.join(relative_path)
       
   258     }
       
   259 
       
   260     pub fn read(
       
   261         &self,
       
   262         relative_path: impl AsRef<Path>,
       
   263     ) -> Result<Vec<u8>, HgError> {
       
   264         let path = self.join(relative_path);
       
   265         std::fs::read(&path).when_reading_file(&path)
       
   266     }
       
   267 
       
   268     pub fn mmap_open(
       
   269         &self,
       
   270         relative_path: impl AsRef<Path>,
       
   271     ) -> Result<Mmap, HgError> {
       
   272         let path = self.base.join(relative_path);
       
   273         let file = std::fs::File::open(&path).when_reading_file(&path)?;
       
   274         // TODO: what are the safety requirements here?
       
   275         let mmap = unsafe { MmapOptions::new().map(&file) }
       
   276             .when_reading_file(&path)?;
       
   277         Ok(mmap)
       
   278     }
       
   279 
       
   280     pub fn rename(
       
   281         &self,
       
   282         relative_from: impl AsRef<Path>,
       
   283         relative_to: impl AsRef<Path>,
       
   284     ) -> Result<(), HgError> {
       
   285         let from = self.join(relative_from);
       
   286         let to = self.join(relative_to);
       
   287         std::fs::rename(&from, &to)
       
   288             .with_context(|| IoErrorContext::RenamingFile { from, to })
       
   289     }
       
   290 }
       
   291 
       
   292 fn fs_metadata(
       
   293     path: impl AsRef<Path>,
       
   294 ) -> Result<Option<std::fs::Metadata>, HgError> {
       
   295     let path = path.as_ref();
       
   296     match std::fs::metadata(path) {
       
   297         Ok(meta) => Ok(Some(meta)),
       
   298         Err(error) => match error.kind() {
       
   299             // TODO: when we require a Rust version where `NotADirectory` is
       
   300             // stable, invert this logic and return None for it and `NotFound`
       
   301             // and propagate any other error.
       
   302             ErrorKind::PermissionDenied => Err(error).with_context(|| {
       
   303                 IoErrorContext::ReadingMetadata(path.to_owned())
       
   304             }),
       
   305             _ => Ok(None),
       
   306         },
       
   307     }
       
   308 }
       
   309 
       
   310 fn is_dir(path: impl AsRef<Path>) -> Result<bool, HgError> {
       
   311     Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_dir()))
       
   312 }
       
   313 
       
   314 fn is_file(path: impl AsRef<Path>) -> Result<bool, HgError> {
       
   315     Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_file()))
       
   316 }