Skip to content

Commit

Permalink
Bring back some notion of vendored-stub-file "metadata"
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexWaygood committed Jun 17, 2024
1 parent df248ce commit 96159d9
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 65 deletions.
51 changes: 1 addition & 50 deletions crates/ruff_db/src/file_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::ops::Deref;
use std::path::{Path, StripPrefixError};

use camino::{Utf8Path, Utf8PathBuf};
use filetime::FileTime;

use crate::metadata::FileRevision;
pub use memory::MemoryFileSystem;
pub use os::OsFileSystem;

Expand Down Expand Up @@ -514,55 +514,6 @@ impl Metadata {
}
}

/// A number representing the revision of a file.
///
/// Two revisions that don't compare equal signify that the file has been modified.
/// Revisions aren't guaranteed to be monotonically increasing or in any specific order.
///
/// Possible revisions are:
/// * The last modification time of the file.
/// * The hash of the file's content.
/// * The revision as it comes from an external system, for example the LSP.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct FileRevision(u128);

impl FileRevision {
pub fn new(value: u128) -> Self {
Self(value)
}

pub const fn zero() -> Self {
Self(0)
}

#[must_use]
pub fn as_u128(self) -> u128 {
self.0
}
}

impl From<u128> for FileRevision {
fn from(value: u128) -> Self {
FileRevision(value)
}
}

impl From<u64> for FileRevision {
fn from(value: u64) -> Self {
FileRevision(u128::from(value))
}
}

impl From<FileTime> for FileRevision {
fn from(value: FileTime) -> Self {
let seconds = value.seconds() as u128;
let seconds = seconds << 64;
let nanos = u128::from(value.nanoseconds());

FileRevision(seconds | nanos)
}
}

#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
pub enum FileType {
File,
Expand Down
1 change: 1 addition & 0 deletions crates/ruff_db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::source::{line_index, source_text};
use crate::vfs::{Vfs, VfsFile};

pub mod file_system;
mod metadata;
pub mod parsed;
pub mod source;
pub mod vendored;
Expand Down
48 changes: 48 additions & 0 deletions crates/ruff_db/src/metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/// A number representing the revision of a file.
///
/// Two revisions that don't compare equal signify that the file has been modified.
/// Revisions aren't guaranteed to be monotonically increasing or in any specific order.
///
/// Possible revisions are:
/// * The last modification time of the file.
/// * The hash of the file's content.
/// * The revision as it comes from an external system, for example the LSP.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct FileRevision(u128);

impl FileRevision {
pub fn new(value: u128) -> Self {
Self(value)
}

pub const fn zero() -> Self {
Self(0)
}

#[must_use]
pub fn as_u128(self) -> u128 {
self.0
}
}

impl From<u128> for FileRevision {
fn from(value: u128) -> Self {
FileRevision(value)
}
}

impl From<u64> for FileRevision {
fn from(value: u64) -> Self {
FileRevision(u128::from(value))
}
}

impl From<filetime::FileTime> for FileRevision {
fn from(value: filetime::FileTime) -> Self {
let seconds = value.seconds() as u128;
let seconds = seconds << 64;
let nanos = u128::from(value.nanoseconds());

FileRevision(seconds | nanos)
}
}
62 changes: 52 additions & 10 deletions crates/ruff_db/src/vendored.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::sync::{Mutex, MutexGuard};
use itertools::Itertools;
use zip::{read::ZipFile, ZipArchive};

use crate::metadata::FileRevision;
pub use path::{VendoredPath, VendoredPathBuf};

pub mod path;
Expand Down Expand Up @@ -33,18 +34,17 @@ impl VendoredFileSystem {
.is_ok()
}

/// Return the crc32 hash of the file or directory
pub fn crc32_hash(&self, path: &VendoredPath) -> Option<u32> {
pub fn metadata(&self, path: &VendoredPath) -> Option<Metadata> {
let normalized = normalize_vendored_path(path);
let inner_locked = self.inner.lock();
let mut archive = inner_locked.borrow_mut();
if let Ok(zip_file) = archive.lookup_path(&normalized) {
return Some(zip_file.crc32());
return Some(Metadata::from_zip_file(zip_file));
}
archive
.lookup_path(&normalized.with_trailing_slash())
.map(|zip_file| zip_file.crc32())
.ok()
if let Ok(zip_file) = archive.lookup_path(&normalized.with_trailing_slash()) {
return Some(Metadata::from_zip_file(zip_file));
}
None
}

/// Read the entire contents of the path into a string
Expand All @@ -58,6 +58,46 @@ impl VendoredFileSystem {
}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum FileType {
/// The path exists in the zip archive and represents a vendored file
File,

/// The path exists in the zip archive and represents a vendored directory of files
Directory,
}

impl FileType {
pub const fn is_file(self) -> bool {
matches!(self, Self::File)
}

pub const fn is_directory(self) -> bool {
matches!(self, Self::Directory)
}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Metadata {
pub kind: FileType,
pub revision: FileRevision,
}

impl Metadata {
fn from_zip_file(zip_file: ZipFile) -> Self {
let kind = if zip_file.is_dir() {
FileType::Directory
} else {
FileType::File
};

Self {
kind,
revision: FileRevision::new(u128::from(zip_file.crc32())),
}
}
}

#[derive(Debug)]
struct VendoredFileSystemInner(Mutex<RefCell<VendoredZipArchive>>);

Expand Down Expand Up @@ -197,7 +237,8 @@ mod tests {
let path = VendoredPath::new(dirname);

assert!(mock_typeshed.exists(path));
assert!(mock_typeshed.crc32_hash(path).is_some())
let metadata = mock_typeshed.metadata(path).unwrap();
assert!(metadata.kind.is_directory());
}

#[test]
Expand Down Expand Up @@ -234,7 +275,7 @@ mod tests {
let mock_typeshed = mock_typeshed();
let path = VendoredPath::new(path);
assert!(!mock_typeshed.exists(path));
assert!(mock_typeshed.crc32_hash(path).is_none());
assert!(mock_typeshed.metadata(path).is_none());
assert!(mock_typeshed
.read(path)
.is_err_and(|err| err.to_string().contains("file not found")));
Expand Down Expand Up @@ -262,7 +303,8 @@ mod tests {

fn test_file(mock_typeshed: &VendoredFileSystem, path: &VendoredPath) {
assert!(mock_typeshed.exists(path));
assert!(mock_typeshed.crc32_hash(path).is_some());
let metadata = mock_typeshed.metadata(path).unwrap();
assert!(metadata.kind.is_file());
}

#[test]
Expand Down
11 changes: 6 additions & 5 deletions crates/ruff_db/src/vfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use dashmap::mapref::entry::Entry;
pub use crate::vendored::{VendoredPath, VendoredPathBuf};
pub use path::VfsPath;

use crate::file_system::{FileRevision, FileSystemPath};
use crate::file_system::FileSystemPath;
use crate::metadata::FileRevision;
use crate::vendored::VendoredFileSystem;
use crate::vfs::private::FileStatus;
use crate::{Db, FxDashMap};
Expand Down Expand Up @@ -314,9 +315,9 @@ impl Default for VendoredVfs {
impl VendoredVfs {
fn revision(&self, path: &VendoredPath) -> Option<FileRevision> {
match self {
VendoredVfs::Real(file_system) => file_system
.crc32_hash(path)
.map(|hash| FileRevision::new(u128::from(hash))),
VendoredVfs::Real(file_system) => {
file_system.metadata(path).map(|metadata| metadata.revision)
}
VendoredVfs::Stubbed(stubbed) => stubbed
.contains_key(&path.to_path_buf())
.then_some(FileRevision::new(1)),
Expand Down Expand Up @@ -355,7 +356,7 @@ mod private {

#[cfg(test)]
mod tests {
use crate::file_system::FileRevision;
use crate::metadata::FileRevision;
use crate::tests::TestDb;
use crate::vfs::{system_path_to_file, vendored_path_to_file};

Expand Down

0 comments on commit 96159d9

Please sign in to comment.