rust/hg-core/src/repo.rs
changeset 47956 81aedf1fc897
parent 47952 9cd35c8c6044
child 47958 fc208d6faed3
equal deleted inserted replaced
47955:e834b79def74 47956:81aedf1fc897
     1 use crate::config::{Config, ConfigError, ConfigParseError};
     1 use crate::config::{Config, ConfigError, ConfigParseError};
       
     2 use crate::dirstate::DirstateParents;
       
     3 use crate::dirstate_tree::dirstate_map::DirstateMap;
       
     4 use crate::dirstate_tree::owning::OwningDirstateMap;
     2 use crate::errors::HgError;
     5 use crate::errors::HgError;
       
     6 use crate::errors::HgResultExt;
     3 use crate::exit_codes;
     7 use crate::exit_codes;
     4 use crate::requirements;
     8 use crate::requirements;
     5 use crate::utils::files::get_path_from_bytes;
     9 use crate::utils::files::get_path_from_bytes;
     6 use crate::utils::SliceExt;
    10 use crate::utils::SliceExt;
     7 use crate::vfs::{is_dir, is_file, Vfs};
    11 use crate::vfs::{is_dir, is_file, Vfs};
       
    12 use crate::DirstateError;
       
    13 use std::cell::{Cell, Ref, RefCell, RefMut};
     8 use std::collections::HashSet;
    14 use std::collections::HashSet;
     9 use std::path::{Path, PathBuf};
    15 use std::path::{Path, PathBuf};
    10 
    16 
    11 /// A repository on disk
    17 /// A repository on disk
    12 pub struct Repo {
    18 pub struct Repo {
    13     working_directory: PathBuf,
    19     working_directory: PathBuf,
    14     dot_hg: PathBuf,
    20     dot_hg: PathBuf,
    15     store: PathBuf,
    21     store: PathBuf,
    16     requirements: HashSet<String>,
    22     requirements: HashSet<String>,
    17     config: Config,
    23     config: Config,
       
    24     // None means not known/initialized yet
       
    25     dirstate_parents: Cell<Option<DirstateParents>>,
       
    26     dirstate_map: RefCell<Option<OwningDirstateMap>>,
    18 }
    27 }
    19 
    28 
    20 #[derive(Debug, derive_more::From)]
    29 #[derive(Debug, derive_more::From)]
    21 pub enum RepoError {
    30 pub enum RepoError {
    22     NotFound {
    31     NotFound {
   184             requirements: reqs,
   193             requirements: reqs,
   185             working_directory,
   194             working_directory,
   186             store: store_path,
   195             store: store_path,
   187             dot_hg,
   196             dot_hg,
   188             config: repo_config,
   197             config: repo_config,
       
   198             dirstate_parents: Cell::new(None),
       
   199             dirstate_map: RefCell::new(None),
   189         };
   200         };
   190 
   201 
   191         requirements::check(&repo)?;
   202         requirements::check(&repo)?;
   192 
   203 
   193         Ok(repo)
   204         Ok(repo)
   226     pub fn has_dirstate_v2(&self) -> bool {
   237     pub fn has_dirstate_v2(&self) -> bool {
   227         self.requirements
   238         self.requirements
   228             .contains(requirements::DIRSTATE_V2_REQUIREMENT)
   239             .contains(requirements::DIRSTATE_V2_REQUIREMENT)
   229     }
   240     }
   230 
   241 
   231     pub fn dirstate_parents(
   242     fn dirstate_file_contents(&self) -> Result<Vec<u8>, HgError> {
   232         &self,
   243         Ok(self
   233     ) -> Result<crate::dirstate::DirstateParents, HgError> {
   244             .hg_vfs()
   234         let dirstate = self.hg_vfs().mmap_open("dirstate")?;
   245             .read("dirstate")
   235         if dirstate.is_empty() {
   246             .io_not_found_as_none()?
   236             return Ok(crate::dirstate::DirstateParents::NULL);
   247             .unwrap_or(Vec::new()))
   237         }
   248     }
   238         let parents = if self.has_dirstate_v2() {
   249 
       
   250     pub fn dirstate_parents(&self) -> Result<DirstateParents, HgError> {
       
   251         if let Some(parents) = self.dirstate_parents.get() {
       
   252             return Ok(parents);
       
   253         }
       
   254         let dirstate = self.dirstate_file_contents()?;
       
   255         let parents = if dirstate.is_empty() {
       
   256             DirstateParents::NULL
       
   257         } else if self.has_dirstate_v2() {
   239             crate::dirstate_tree::on_disk::read_docket(&dirstate)?.parents()
   258             crate::dirstate_tree::on_disk::read_docket(&dirstate)?.parents()
   240         } else {
   259         } else {
   241             crate::dirstate::parsers::parse_dirstate_parents(&dirstate)?
   260             crate::dirstate::parsers::parse_dirstate_parents(&dirstate)?
   242                 .clone()
   261                 .clone()
   243         };
   262         };
       
   263         self.dirstate_parents.set(Some(parents));
   244         Ok(parents)
   264         Ok(parents)
   245     }
   265     }
   246 }
   266 
       
   267     fn new_dirstate_map(&self) -> Result<OwningDirstateMap, DirstateError> {
       
   268         let dirstate_file_contents = self.dirstate_file_contents()?;
       
   269         if dirstate_file_contents.is_empty() {
       
   270             self.dirstate_parents.set(Some(DirstateParents::NULL));
       
   271             Ok(OwningDirstateMap::new_empty(Vec::new()))
       
   272         } else if self.has_dirstate_v2() {
       
   273             let docket = crate::dirstate_tree::on_disk::read_docket(
       
   274                 &dirstate_file_contents,
       
   275             )?;
       
   276             self.dirstate_parents.set(Some(docket.parents()));
       
   277             let data_size = docket.data_size();
       
   278             let metadata = docket.tree_metadata();
       
   279             let mut map = if let Some(data_mmap) = self
       
   280                 .hg_vfs()
       
   281                 .mmap_open(docket.data_filename())
       
   282                 .io_not_found_as_none()?
       
   283             {
       
   284                 OwningDirstateMap::new_empty(MmapWrapper(data_mmap))
       
   285             } else {
       
   286                 OwningDirstateMap::new_empty(Vec::new())
       
   287             };
       
   288             let (on_disk, placeholder) = map.get_mut_pair();
       
   289             *placeholder = DirstateMap::new_v2(on_disk, data_size, metadata)?;
       
   290             Ok(map)
       
   291         } else {
       
   292             let mut map = OwningDirstateMap::new_empty(dirstate_file_contents);
       
   293             let (on_disk, placeholder) = map.get_mut_pair();
       
   294             let (inner, parents) = DirstateMap::new_v1(on_disk)?;
       
   295             self.dirstate_parents
       
   296                 .set(Some(parents.unwrap_or(DirstateParents::NULL)));
       
   297             *placeholder = inner;
       
   298             Ok(map)
       
   299         }
       
   300     }
       
   301 
       
   302     pub fn dirstate_map(
       
   303         &self,
       
   304     ) -> Result<Ref<OwningDirstateMap>, DirstateError> {
       
   305         let mut borrowed = self.dirstate_map.borrow();
       
   306         if borrowed.is_none() {
       
   307             drop(borrowed);
       
   308             // Only use `borrow_mut` if it is really needed to avoid panic in
       
   309             // case there is another outstanding borrow but mutation is not
       
   310             // needed.
       
   311             *self.dirstate_map.borrow_mut() = Some(self.new_dirstate_map()?);
       
   312             borrowed = self.dirstate_map.borrow()
       
   313         }
       
   314         Ok(Ref::map(borrowed, |option| option.as_ref().unwrap()))
       
   315     }
       
   316 
       
   317     pub fn dirstate_map_mut(
       
   318         &self,
       
   319     ) -> Result<RefMut<OwningDirstateMap>, DirstateError> {
       
   320         let mut borrowed = self.dirstate_map.borrow_mut();
       
   321         if borrowed.is_none() {
       
   322             *borrowed = Some(self.new_dirstate_map()?);
       
   323         }
       
   324         Ok(RefMut::map(borrowed, |option| option.as_mut().unwrap()))
       
   325     }
       
   326 }
       
   327 
       
   328 // TODO: remove this when https://github.com/RazrFalcon/memmap2-rs/pull/22 is on crates.io
       
   329 struct MmapWrapper(memmap2::Mmap);
       
   330 
       
   331 impl std::ops::Deref for MmapWrapper {
       
   332     type Target = [u8];
       
   333 
       
   334     fn deref(&self) -> &[u8] {
       
   335         self.0.deref()
       
   336     }
       
   337 }
       
   338 
       
   339 unsafe impl stable_deref_trait::StableDeref for MmapWrapper {}