rust/hg-core/src/repo.rs
changeset 48421 2097f63575a5
parent 48420 c7c23bb036c9
child 48510 7f633432ca92
equal deleted inserted replaced
48420:c7c23bb036c9 48421:2097f63575a5
     1 use crate::changelog::Changelog;
     1 use crate::changelog::Changelog;
     2 use crate::config::{Config, ConfigError, ConfigParseError};
     2 use crate::config::{Config, ConfigError, ConfigParseError};
     3 use crate::dirstate::DirstateParents;
     3 use crate::dirstate::DirstateParents;
     4 use crate::dirstate_tree::dirstate_map::DirstateMap;
     4 use crate::dirstate_tree::dirstate_map::DirstateMap;
       
     5 use crate::dirstate_tree::on_disk::Docket as DirstateDocket;
     5 use crate::dirstate_tree::owning::OwningDirstateMap;
     6 use crate::dirstate_tree::owning::OwningDirstateMap;
     6 use crate::errors::HgError;
       
     7 use crate::errors::HgResultExt;
     7 use crate::errors::HgResultExt;
       
     8 use crate::errors::{HgError, IoResultExt};
     8 use crate::exit_codes;
     9 use crate::exit_codes;
     9 use crate::lock::{try_with_lock_no_wait, LockError};
    10 use crate::lock::{try_with_lock_no_wait, LockError};
    10 use crate::manifest::{Manifest, Manifestlog};
    11 use crate::manifest::{Manifest, Manifestlog};
    11 use crate::revlog::filelog::Filelog;
    12 use crate::revlog::filelog::Filelog;
    12 use crate::revlog::revlog::RevlogError;
    13 use crate::revlog::revlog::RevlogError;
    16 use crate::vfs::{is_dir, is_file, Vfs};
    17 use crate::vfs::{is_dir, is_file, Vfs};
    17 use crate::{requirements, NodePrefix};
    18 use crate::{requirements, NodePrefix};
    18 use crate::{DirstateError, Revision};
    19 use crate::{DirstateError, Revision};
    19 use std::cell::{Ref, RefCell, RefMut};
    20 use std::cell::{Ref, RefCell, RefMut};
    20 use std::collections::HashSet;
    21 use std::collections::HashSet;
       
    22 use std::io::Seek;
       
    23 use std::io::SeekFrom;
       
    24 use std::io::Write as IoWrite;
    21 use std::path::{Path, PathBuf};
    25 use std::path::{Path, PathBuf};
    22 
    26 
    23 /// A repository on disk
    27 /// A repository on disk
    24 pub struct Repo {
    28 pub struct Repo {
    25     working_directory: PathBuf,
    29     working_directory: PathBuf,
   414     }
   418     }
   415 
   419 
   416     pub fn filelog(&self, path: &HgPath) -> Result<Filelog, HgError> {
   420     pub fn filelog(&self, path: &HgPath) -> Result<Filelog, HgError> {
   417         Filelog::open(self, path)
   421         Filelog::open(self, path)
   418     }
   422     }
       
   423 
       
   424     /// Write to disk any updates that were made through `dirstate_map_mut`.
       
   425     ///
       
   426     /// The "wlock" must be held while calling this.
       
   427     /// See for example `try_with_wlock_no_wait`.
       
   428     ///
       
   429     /// TODO: have a `WritableRepo` type only accessible while holding the
       
   430     /// lock?
       
   431     pub fn write_dirstate(&self) -> Result<(), DirstateError> {
       
   432         let map = self.dirstate_map()?;
       
   433         // TODO: Maintain a `DirstateMap::dirty` flag, and return early here if
       
   434         // it’s unset
       
   435         let parents = self.dirstate_parents()?;
       
   436         let packed_dirstate = if self.has_dirstate_v2() {
       
   437             let uuid = self.dirstate_data_file_uuid.get_or_init(self)?;
       
   438             let mut uuid = uuid.as_ref();
       
   439             let can_append = uuid.is_some();
       
   440             let (data, tree_metadata, append) = map.pack_v2(can_append)?;
       
   441             if !append {
       
   442                 uuid = None
       
   443             }
       
   444             let uuid = if let Some(uuid) = uuid {
       
   445                 std::str::from_utf8(uuid)
       
   446                     .map_err(|_| {
       
   447                         HgError::corrupted("non-UTF-8 dirstate data file ID")
       
   448                     })?
       
   449                     .to_owned()
       
   450             } else {
       
   451                 DirstateDocket::new_uid()
       
   452             };
       
   453             let data_filename = format!("dirstate.{}", uuid);
       
   454             let data_filename = self.hg_vfs().join(data_filename);
       
   455             let mut options = std::fs::OpenOptions::new();
       
   456             if append {
       
   457                 options.append(true);
       
   458             } else {
       
   459                 options.write(true).create_new(true);
       
   460             }
       
   461             let data_size = (|| {
       
   462                 // TODO: loop and try another random ID if !append and this
       
   463                 // returns `ErrorKind::AlreadyExists`? Collision chance of two
       
   464                 // random IDs is one in 2**32
       
   465                 let mut file = options.open(&data_filename)?;
       
   466                 file.write_all(&data)?;
       
   467                 file.flush()?;
       
   468                 // TODO: use https://doc.rust-lang.org/std/io/trait.Seek.html#method.stream_position when we require Rust 1.51+
       
   469                 file.seek(SeekFrom::Current(0))
       
   470             })()
       
   471             .when_writing_file(&data_filename)?;
       
   472             DirstateDocket::serialize(
       
   473                 parents,
       
   474                 tree_metadata,
       
   475                 data_size,
       
   476                 uuid.as_bytes(),
       
   477             )
       
   478             .map_err(|_: std::num::TryFromIntError| {
       
   479                 HgError::corrupted("overflow in dirstate docket serialization")
       
   480             })?
       
   481         } else {
       
   482             map.pack_v1(parents)?
       
   483         };
       
   484         self.hg_vfs().atomic_write("dirstate", &packed_dirstate)?;
       
   485         Ok(())
       
   486     }
   419 }
   487 }
   420 
   488 
   421 /// Lazily-initialized component of `Repo` with interior mutability
   489 /// Lazily-initialized component of `Repo` with interior mutability
   422 ///
   490 ///
   423 /// This differs from `OnceCell` in that the value can still be "deinitialized"
   491 /// This differs from `OnceCell` in that the value can still be "deinitialized"