Refactor:Mv mod visitor vfs under crates_io

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
Jiahao XU 2022-06-21 13:44:12 +10:00
parent b6f15f2e5e
commit 23bad39ba8
No known key found for this signature in database
GPG key ID: 591C0B03040416D6
4 changed files with 6 additions and 6 deletions

View file

@ -0,0 +1,52 @@
use std::collections::{hash_map::HashMap, hash_set::HashSet};
use std::io;
use std::path::Path;
use cargo_toml::AbstractFilesystem;
use crate::helpers::PathExt;
/// This type stores the filesystem structure for the crate tarball
/// extracted in memory and can be passed to
/// `cargo_toml::Manifest::complete_from_abstract_filesystem`.
#[derive(Debug)]
pub(super) struct Vfs(HashMap<Box<Path>, HashSet<Box<str>>>);
impl Vfs {
pub(super) fn new() -> Self {
Self(HashMap::with_capacity(16))
}
/// * `path` - must be canonical, must not be empty.
pub(super) fn add_path(&mut self, mut path: &Path) {
while let Some(parent) = path.parent() {
// Since path has parent, it must have a filename
let filename = path.file_name().unwrap();
// `cargo_toml`'s implementation does the same thing.
// https://docs.rs/cargo_toml/0.11.5/src/cargo_toml/afs.rs.html#24
let filename = filename.to_string_lossy();
self.0
.entry(parent.into())
.or_insert_with(|| HashSet::with_capacity(4))
.insert(filename.into());
path = parent;
}
}
}
impl AbstractFilesystem for Vfs {
fn file_names_in(&self, rel_path: &str) -> io::Result<HashSet<Box<str>>> {
let rel_path = Path::new(rel_path).normalize_path();
Ok(self.0.get(&*rel_path).map(Clone::clone).unwrap_or_default())
}
}
impl AbstractFilesystem for &Vfs {
fn file_names_in(&self, rel_path: &str) -> io::Result<HashSet<Box<str>>> {
(*self).file_names_in(rel_path)
}
}

View file

@ -0,0 +1,81 @@
use std::io::Read;
use std::path::{Path, PathBuf};
use cargo_toml::Manifest;
use log::debug;
use tar::Entries;
use super::vfs::Vfs;
use crate::{
helpers::{PathExt, TarEntriesVisitor},
BinstallError, Meta,
};
#[derive(Debug)]
pub(super) struct ManifestVisitor {
cargo_toml_content: Vec<u8>,
/// manifest_dir_path is treated as the current dir.
manifest_dir_path: PathBuf,
vfs: Vfs,
}
impl ManifestVisitor {
pub(super) fn new(manifest_dir_path: PathBuf) -> Self {
Self {
// Cargo.toml is quite large usually.
cargo_toml_content: Vec::with_capacity(2000),
manifest_dir_path,
vfs: Vfs::new(),
}
}
/// Load binstall metadata using the extracted information stored in memory.
pub(super) fn load_manifest(&self) -> Result<Manifest<Meta>, BinstallError> {
debug!("Loading manifest directly from extracted file");
// Load and parse manifest
let mut manifest = Manifest::<Meta>::from_slice_with_metadata(&self.cargo_toml_content)?;
// Checks vfs for binary output names
manifest.complete_from_abstract_filesystem(&self.vfs)?;
// Return metadata
Ok(manifest)
}
}
impl TarEntriesVisitor for ManifestVisitor {
fn visit<R: Read>(&mut self, entries: Entries<'_, R>) -> Result<(), BinstallError> {
for res in entries {
let mut entry = res?;
let path = entry.path()?;
let path = path.normalize_path();
let path = if let Ok(path) = path.strip_prefix(&self.manifest_dir_path) {
path
} else {
// The path is outside of the curr dir (manifest dir),
// ignore it.
continue;
};
if path == Path::new("Cargo.toml")
|| path == Path::new("src/main.rs")
|| path.starts_with("src/bin")
{
self.vfs.add_path(path);
}
if path == Path::new("Cargo.toml") {
// Since it is possible for the same Cargo.toml to appear
// multiple times using `tar --keep-old-files`, here we
// clear the buffer first before reading into it.
self.cargo_toml_content.clear();
entry.read_to_end(&mut self.cargo_toml_content)?;
}
}
Ok(())
}
}