rust/hg-core/src/vfs.rs
author Simon Sapin <simon.sapin@octobus.net>
Mon, 13 Sep 2021 18:09:10 +0200
changeset 47964 796206e74b10
parent 47955 e834b79def74
child 48199 9d0e5629cfbf
permissions -rw-r--r--
rhg: Reuse manifest when checking status of multiple ambiguous files When `rhg status` cannot determine whether a file is clean based on mtime and size alone, it needs to compare its contents with those found in the parent commit. Previously, rhg would find the (same) manifest of that commit again for every such file. This is lifted out of the loop and reused. Differential Revision: https://phab.mercurial-scm.org/D11411
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
47952
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     1
use crate::errors::{HgError, IoErrorContext, IoResultExt};
47955
e834b79def74 rust: Switch to the memmap2-rs crate
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
     2
use memmap2::{Mmap, MmapOptions};
47952
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     3
use std::io::ErrorKind;
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     4
use std::path::{Path, PathBuf};
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     5
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     6
/// Filesystem access abstraction for the contents of a given "base" diretory
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     7
#[derive(Clone, Copy)]
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     8
pub struct Vfs<'a> {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     9
    pub(crate) base: &'a Path,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    10
}
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    11
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    12
impl Vfs<'_> {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    13
    pub fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    14
        self.base.join(relative_path)
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    15
    }
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    16
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    17
    pub fn read(
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    18
        &self,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    19
        relative_path: impl AsRef<Path>,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    20
    ) -> Result<Vec<u8>, HgError> {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    21
        let path = self.join(relative_path);
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    22
        std::fs::read(&path).when_reading_file(&path)
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    23
    }
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    24
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    25
    pub fn mmap_open(
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    26
        &self,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    27
        relative_path: impl AsRef<Path>,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    28
    ) -> Result<Mmap, HgError> {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    29
        let path = self.base.join(relative_path);
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    30
        let file = std::fs::File::open(&path).when_reading_file(&path)?;
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    31
        // TODO: what are the safety requirements here?
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    32
        let mmap = unsafe { MmapOptions::new().map(&file) }
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    33
            .when_reading_file(&path)?;
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    34
        Ok(mmap)
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    35
    }
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    36
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    37
    pub fn rename(
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    38
        &self,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    39
        relative_from: impl AsRef<Path>,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    40
        relative_to: impl AsRef<Path>,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    41
    ) -> Result<(), HgError> {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    42
        let from = self.join(relative_from);
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    43
        let to = self.join(relative_to);
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    44
        std::fs::rename(&from, &to)
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    45
            .with_context(|| IoErrorContext::RenamingFile { from, to })
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    46
    }
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    47
}
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    48
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    49
fn fs_metadata(
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    50
    path: impl AsRef<Path>,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    51
) -> Result<Option<std::fs::Metadata>, HgError> {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    52
    let path = path.as_ref();
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    53
    match std::fs::metadata(path) {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    54
        Ok(meta) => Ok(Some(meta)),
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    55
        Err(error) => match error.kind() {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    56
            // TODO: when we require a Rust version where `NotADirectory` is
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    57
            // stable, invert this logic and return None for it and `NotFound`
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    58
            // and propagate any other error.
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    59
            ErrorKind::PermissionDenied => Err(error).with_context(|| {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    60
                IoErrorContext::ReadingMetadata(path.to_owned())
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    61
            }),
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    62
            _ => Ok(None),
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    63
        },
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    64
    }
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    65
}
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    66
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    67
pub(crate) fn is_dir(path: impl AsRef<Path>) -> Result<bool, HgError> {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    68
    Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_dir()))
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    69
}
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    70
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    71
pub(crate) fn is_file(path: impl AsRef<Path>) -> Result<bool, HgError> {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    72
    Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_file()))
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    73
}